From a4163512ff17e12405969e94856e45ad172f53f1 Mon Sep 17 00:00:00 2001 From: LJ <81748770+elle-j@users.noreply.github.com> Date: Wed, 28 Jan 2026 23:04:22 +0100 Subject: [PATCH] Improve compilation time in standard JSON mode and honor requested output (#461) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Description Compilation times for resolc were significantly slower than solc when: * Multiple files were included in the JSON input file via `--standard-json` * And none of the files requested code generation * (If only a subset of files requested code generation, both resolc and solc were very slow) Reason: * Resolc unconditionally generated bytecode for all contracts, even if not requested. * When compiling to PolkaVM bytecode, we need to pass additional flags (e.g. `irOptimized`) to solc. If these flags were not explicitly requested, resolc also added these to the requested output since PolkaVM bytecode was always generated. ## Breaking Changes The following changes are breaking, but fix the semantics to match its intended behavior: * Compiling with `--standard-json` now compiles to PolkaVM bytecode ***only*** for the contracts explicitly requested in the `outputSelection`. * Compiling with `--standard-json` now outputs ***only*** the explicitly requested output (e.g. `evm.assembly`, `evm.bytecode`, `ast`, etc.). ```jsonc // Example: { "settings": { // ... "outputSelection": { "src/common/GasService.sol": { // Contracts in this file will generate bytecode. // Only these fields of the JSON output selection will be in the `contracts` output. "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"], // Only this field of the JSON output selection will be in the `sources` output. "": ["ast"] }, "src/common/Gateway.sol": { // No contracts in this file will generate bytecode. "*": ["abi", "evm.methodIdentifiers", "metadata"], // No `ast` will be in the `sources` output (only the automatically added `id`, // similar to solc as this is not a configurable output selection). "": [] }, } } } ``` ## Performance Improvements When e.g. the standard JSON input file includes multiple files and requests output for every contract as per this setting: ```jsonc { "settings": { // ... "optimizer": { "enabled": true, "runs": 1 }, "viaIR": true, "outputSelection": { "src/common/GasService.sol": { "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"], }, // Rest of files.. } } } ``` The differences in compilation times depending on whether `evm.bytecode` is selected in every file, one file, or no files can be seen below: | Solc Optimizer (runs=1) | ViaIR | Request `abi`, `evm.methodIdentifiers`, `metadata` | Request `evm.bytecode` | resolc before | resolc after | solc v0.8.33 | |:-----------------------:|:-----:|:---------:|:---------:|:-------------:|:------------:|:----------:| | ✅ | ✅ | All files | All files | `~14.5s` | `~14.5s` | `~13.5s` | | ✅ | ✅ | All files | One file | `~14.5s` | `~450ms` | `~13.5s` | | ✅ | ✅ | All files | No files | `~14.5s` | `~390ms` | `~350ms` | **Observations:** * `resolc before` is roughly the same no matter the request * This is due to unconditionally generating bytecode * When not requesting bytecode for any contracts: * `resolc after` now compiles in ~390ms (vs ~14.5s), similar to `solc` * Neither `solc` nor `resolc after` generates bytecode when none of the contracts request it * When requesting bytecode for all contracts in _only one_ file: * `resolc after` now compiles in ~450ms (vs ~14.5s) * `solc` still compiles in the same time as when requesting bytecode for all contracts in all files * This is something they have tried to improve (see [Solidity#15373](https://github.com/argotorg/solidity/issues/15373) and [Solidity#15615](https://github.com/argotorg/solidity/issues/15615)), and the intended behavior seems to now be that bytecode should only be generated when explicitly requested for each contract. * Even though PRs have merged to try to fix it, their issue seems to persist as of v0.8.33. # Open Questions * Foundry: * [x] Pruning of the AST: * Just saw [this past commit](https://github.com/paritytech/revive/pull/385) to not prune the AST for Foundry compatibility. * Can Foundry not explicitly request `"": "ast"`? * **Answer:** * Pruning the AST when not requested should be fine, as long as Foundry explicitly requests it when needed. * Will be tested by Foundry maintainer. # Review Notes Changes in `docs/` (~25 files) can be skipped as they are automatically updated after adding content to `book/` and rebuilding it. # Resolved Issues Closes #326 --------- Co-authored-by: xermicus --- .github/workflows/benchmark.yml | 6 +- .github/workflows/reusable-build.yml | 9 +- CHANGELOG.md | 26 + book/src/user_guide/std_json.md | 73 +- crates/resolc/BENCHMARKS_M4PRO.md | 50 +- crates/resolc/benches/compile.rs | 53 +- crates/resolc/src/cli_utils.rs | 37 + crates/resolc/src/lib.rs | 44 +- crates/resolc/src/tests/cli/standard_json.rs | 399 +++++++++- .../tests/data/standard_json/all_outputs.json | 115 +++ .../no_pvm_codegen_per_file.json | 720 ++++++++++++++++++ .../pvm_codegen_all_wildcard.json | 375 +++++++++ .../standard_json/pvm_codegen_one_file.json | 720 ++++++++++++++++++ .../standard_json/pvm_codegen_per_file.json | 720 ++++++++++++++++++ .../standard_json/solidity_contracts.json | 14 +- .../standard_json/yul_no_pvm_codegen.json | 23 + .../data/standard_json/yul_pvm_codegen.json | 23 + crates/resolc/src/tests/unit/standard_json.rs | 117 ++- .../input/settings/selection/file/flag.rs | 47 +- .../input/settings/selection/file/mod.rs | 82 +- .../input/settings/selection/mod.rs | 73 +- .../src/standard_json/output/contract/mod.rs | 59 ++ .../src/standard_json/output/mod.rs | 41 +- .../src/standard_json/output/source.rs | 8 +- docs/404.html | 2 +- docs/developer_guide.html | 2 +- docs/developer_guide/architecture.html | 2 +- docs/developer_guide/contributing.html | 2 +- docs/developer_guide/cross_compilation.html | 2 +- docs/developer_guide/target.html | 2 +- docs/developer_guide/testing.html | 2 +- docs/faq.html | 2 +- docs/index.html | 2 +- docs/print.html | 65 +- docs/revive_runner.html | 2 +- docs/roadmap.html | 2 +- docs/searcher-c2a407aa.js | 2 +- docs/searchindex-575cfd18.js | 1 + docs/searchindex-c7304031.js | 1 - docs/user_guide.html | 2 +- docs/user_guide/cli.html | 2 +- docs/user_guide/differences.html | 2 +- docs/user_guide/installation.html | 2 +- docs/user_guide/js.html | 2 +- docs/user_guide/rust_libraries.html | 2 +- docs/user_guide/std_json.html | 65 +- docs/user_guide/tooling.html | 2 +- docs/welcome.html | 2 +- js/emscripten/fixtures/instantiate.json | 2 +- .../fixtures/instantiate_tokens.json | 2 +- js/emscripten/fixtures/storage.json | 2 +- js/emscripten/fixtures/token.json | 2 +- 52 files changed, 3827 insertions(+), 187 deletions(-) create mode 100644 crates/resolc/src/tests/data/standard_json/all_outputs.json create mode 100644 crates/resolc/src/tests/data/standard_json/no_pvm_codegen_per_file.json create mode 100644 crates/resolc/src/tests/data/standard_json/pvm_codegen_all_wildcard.json create mode 100644 crates/resolc/src/tests/data/standard_json/pvm_codegen_one_file.json create mode 100644 crates/resolc/src/tests/data/standard_json/pvm_codegen_per_file.json create mode 100644 crates/resolc/src/tests/data/standard_json/yul_no_pvm_codegen.json create mode 100644 crates/resolc/src/tests/data/standard_json/yul_pvm_codegen.json create mode 100644 docs/searchindex-575cfd18.js delete mode 100644 docs/searchindex-c7304031.js diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index dab4fe7..63f6d7f 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -42,7 +42,7 @@ jobs: - name: Install Node.js uses: actions/setup-node@v6 with: - node-version: 'lts/*' + node-version: "lts/*" - name: Install Benchmarking Tools run: | @@ -71,7 +71,7 @@ jobs: cargo bench --package resolc --bench compile -- --save-baseline resolc_before cargo bench --package revive-benchmarks --bench parse -- --save-baseline yul_parse_before cargo bench --package revive-benchmarks --bench lower -- --save-baseline yul_lower_before - timeout-minutes: 20 + timeout-minutes: 40 - name: Checkout Commit After Changes run: | @@ -95,7 +95,7 @@ jobs: cargo bench --package resolc --bench compile -- --save-baseline resolc_changes cargo bench --package revive-benchmarks --bench parse -- --save-baseline yul_parse_changes cargo bench --package revive-benchmarks --bench lower -- --save-baseline yul_lower_changes - timeout-minutes: 20 + timeout-minutes: 40 - name: Compare Benchmarks run: | diff --git a/.github/workflows/reusable-build.yml b/.github/workflows/reusable-build.yml index 4b9ec31..fa52283 100644 --- a/.github/workflows/reusable-build.yml +++ b/.github/workflows/reusable-build.yml @@ -196,7 +196,14 @@ jobs: content: 'pragma solidity ^0.8.0; contract MyContract { function greet() public pure returns (string memory) { return \'Hello\'; } }', }, }, - settings: { optimizer: { enabled: false } } + settings: { + optimizer: { enabled: false }, + outputSelection: { + '*': { + '*': ['evm.bytecode'] + } + } + } }; compiler.writeToStdin(JSON.stringify(standardJsonInput)); diff --git a/CHANGELOG.md b/CHANGELOG.md index e48409d..5f61b3e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,32 @@ Supported `polkadot-sdk` rev: `unstable2507` ### Fixed - OOB access in `calldataload` and `calldatacopy` should always produce zero values instead of consuming all gas. - The superfluous byte swap in `linkersymbol`. +- Compiling with `--standard-json` now compiles to PolkaVM bytecode _only_ for the contracts explicitly requested in the `outputSelection`, significantly improving compilation time when none or a subset of files requests bytecode. [PR#461](https://github.com/paritytech/revive/pull/461) +- Compiling with `--standard-json` now outputs _only_ the explicitly requested output (e.g. `evm.assembly`, `evm.bytecode`, `ast`, etc.). [PR#461](https://github.com/paritytech/revive/pull/461) +```jsonc +// Example: +{ + "settings": { + // ... + "outputSelection": { + "path/to/my/file1.sol": { + // Contracts in this file will generate bytecode. + // Only these fields of the JSON output selection will be in the `contracts` output. + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"], + // Only this field of the JSON output selection will be in the `sources` output. + "": ["ast"] + }, + "path/to/my/file2.sol": { + // No contracts in this file will generate bytecode. + "*": ["abi", "evm.methodIdentifiers", "metadata"], + // No `ast` will be in the `sources` output (only the automatically added `id`, + // similar to solc as this is not a configurable output selection). + "": [] + }, + } + } +} +``` ## v0.6.0 diff --git a/book/src/user_guide/std_json.md b/book/src/user_guide/std_json.md index 1e6562c..ac17496 100644 --- a/book/src/user_guide/std_json.md +++ b/book/src/user_guide/std_json.md @@ -1,6 +1,6 @@ # Standard JSON interface -The `revive` compiler is mostly compatible with the `solc` standard JSON interface. There are a few additional (PVM related) __input__ configurations: +The `revive` compiler is mostly compatible with the `solc` standard JSON interface. There are a few differences and additional (PVM related) __input__ configurations: ## The `settings.polkavm` object @@ -14,11 +14,11 @@ A boolean value allowing to enable debug information. Corresponds to `resolc -g` Used to apply PVM specific memory configuration settings. -#### `settings.polkavm.memoryConifg.heapSize` +#### `settings.polkavm.memoryConfig.heapSize` A numerical value allowing to configure the contract heap size. Corresponds to `resolc --heap-size`. -#### `settings.polkavm.memoryConifg.stackSize` +#### `settings.polkavm.memoryConfig.stackSize` A numerical value allowing to configure the contract stack size. Corresponds to `resolc --stack-size`. @@ -34,3 +34,70 @@ A single char value to configure the LLVM optimizer settings. Corresponds to `re Allows to specify arbitrary command line arguments to LLVM initialization. Used mainly for development and debugging purposes. +## The `settings.outputSelection` object + +Used to select desired outputs. + +### The "all" (`*`) wildcard + +Resolc supports the "all" (`*`) wildcard for the file-level (first-level) and contract-level (second-level) keys. A file-level key can be either the wildcard or a specific file name, whereas the contract-level key can only be the wildcard for robustness reasons. + +Thus, output can be requested in 2 ways: + +```json +// All files and all contracts: +{ + "settings": { + "outputSelection": { + "*": { + "*": [/* specific contract-level output fields */], + "": [/* specific file-level output fields */] + } + } + } +} + +// Specific files and all their contracts: +{ + "settings": { + "outputSelection": { + "path/to/my/file.sol": { + "*": [/* specific contract-level output fields */], + "": [/* specific file-level output fields */] + }, + // Rest of files... + } + } +} +``` + +### The contract-level `evm` output selection + +> [!NOTE] +> +> Currently, resolc supports requesting either the full `evm` output, or one more level of specificity, such as `evm.bytecode`. + +When requesting code generation, such as `evm.bytecode` or `evm.assembly`, the resolc compilation process additionally needs `ast`, `metadata`, `irOptimized`, and `evm.methodIdentifiers` selectors. These selectors will be automatically added if code generation is needed, but will only be included in the output if explicitly requested. + +```json +{ + "settings": { + "outputSelection": { + "path/to/my/file1.sol": { + // Contracts in this file will generate bytecode. + // Only these fields of the JSON output selection will be in the `contracts` output. + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"], + // Only this field of the JSON output selection will be in the `sources` output. + "": ["ast"] + }, + "path/to/my/file2.sol": { + // No contracts in this file will generate bytecode. + "*": ["abi", "evm.methodIdentifiers", "metadata"], + // No `ast` will be in the `sources` output (only the automatically added `id`, + // similar to solc as this is not a configurable output selection). + "": [] + }, + } + } +} +``` diff --git a/crates/resolc/BENCHMARKS_M4PRO.md b/crates/resolc/BENCHMARKS_M4PRO.md index 9474b02..6526332 100644 --- a/crates/resolc/BENCHMARKS_M4PRO.md +++ b/crates/resolc/BENCHMARKS_M4PRO.md @@ -6,47 +6,61 @@ - [Empty](#empty) - [Dependency](#dependency) - [LargeDivRem](#largedivrem) - - [Memset (`--yul`)](#memset-(`--yul`)) - - [Return (`--yul`)](#return-(`--yul`)) - - [Multiple Contracts (`--standard-json`)](#multiple-contracts-(`--standard-json`)) + - [Yul Memset](#yul-memset) + - [Yul Return](#yul-return) + - [Std JSON Codegen All Files](#std-json-codegen-all-files) + - [Std JSON Codegen One of Many Files](#std-json-codegen-one-of-many-files) + - [Std JSON No Codegen](#std-json-no-codegen) ## Benchmark Results ### Empty -| | `resolc` | `solc` | -|:-------|:-------------------------|:------------------------------- | -| | `62.77 ms` (✅ **1.00x**) | `9.63 ms` (🚀 **6.52x faster**) | +| | `resolc` | `solc` | +|:-------|:-------------------------|:-------------------------------- | +| | `59.86 ms` (✅ **1.00x**) | `11.44 ms` (🚀 **5.23x faster**) | ### Dependency | | `resolc` | `solc` | |:-------|:--------------------------|:-------------------------------- | -| | `142.28 ms` (✅ **1.00x**) | `57.57 ms` (🚀 **2.47x faster**) | +| | `164.51 ms` (✅ **1.00x**) | `68.47 ms` (🚀 **2.40x faster**) | ### LargeDivRem | | `resolc` | `solc` | |:-------|:--------------------------|:-------------------------------- | -| | `110.80 ms` (✅ **1.00x**) | `20.96 ms` (🚀 **5.29x faster**) | +| | `121.55 ms` (✅ **1.00x**) | `25.67 ms` (🚀 **4.74x faster**) | -### Memset (`--yul`) +### Yul Memset + +| | `resolc` | `solc` | +|:-------|:-------------------------|:-------------------------------- | +| | `63.83 ms` (✅ **1.00x**) | `10.39 ms` (🚀 **6.14x faster**) | + +### Yul Return | | `resolc` | `solc` | |:-------|:-------------------------|:------------------------------- | -| | `58.39 ms` (✅ **1.00x**) | `8.84 ms` (🚀 **6.61x faster**) | +| | `53.55 ms` (✅ **1.00x**) | `8.95 ms` (🚀 **5.99x faster**) | -### Return (`--yul`) +### Std JSON Codegen All Files -| | `resolc` | `solc` | -|:-------|:-------------------------|:------------------------------- | -| | `52.83 ms` (✅ **1.00x**) | `8.04 ms` (🚀 **6.57x faster**) | +| | `resolc` | `solc` | +|:-------|:------------------------|:------------------------------- | +| | `14.59 s` (✅ **1.00x**) | `13.86 s` (✅ **1.05x faster**) | -### Multiple Contracts (`--standard-json`) +### Std JSON Codegen One of Many Files -| | `resolc` | `solc` | -|:-------|:-----------------------|:--------------------------------- | -| | `1.52 s` (✅ **1.00x**) | `623.91 ms` (🚀 **2.44x faster**) | +| | `resolc` | `solc` | +|:-------|:--------------------------|:-------------------------------- | +| | `456.07 ms` (✅ **1.00x**) | `13.78 s` (❌ *30.22x slower*) | + +### Std JSON No Codegen + +| | `resolc` | `solc` | +|:-------|:--------------------------|:--------------------------------- | +| | `365.40 ms` (✅ **1.00x**) | `354.96 ms` (✅ **1.03x faster**) | --- Made with [criterion-table](https://github.com/nu11ptr/criterion-table) diff --git a/crates/resolc/benches/compile.rs b/crates/resolc/benches/compile.rs index 54394fe..f8d1307 100644 --- a/crates/resolc/benches/compile.rs +++ b/crates/resolc/benches/compile.rs @@ -13,7 +13,9 @@ use resolc::{ cli_utils::{ absolute_path, execute_command, ResolcOptSettings, SolcOptSettings, SOLIDITY_CONTRACT_PATH, SOLIDITY_DEPENDENCY_CONTRACT_PATH, SOLIDITY_LARGE_DIV_REM_CONTRACT_PATH, - STANDARD_JSON_CONTRACTS_PATH, YUL_MEMSET_CONTRACT_PATH, YUL_RETURN_CONTRACT_PATH, + STANDARD_JSON_NO_PVM_CODEGEN_PER_FILE_PATH, STANDARD_JSON_PVM_CODEGEN_ONE_FILE_PATH, + STANDARD_JSON_PVM_CODEGEN_PER_FILE_PATH, YUL_MEMSET_CONTRACT_PATH, + YUL_RETURN_CONTRACT_PATH, }, SolcCompiler, }; @@ -79,7 +81,7 @@ fn bench_dependency(c: &mut Criterion) { let mut group = group(c, "Dependency"); group .sample_size(50) - .measurement_time(Duration::from_secs(9)); + .measurement_time(Duration::from_secs(10)); let path = absolute_path(SOLIDITY_DEPENDENCY_CONTRACT_PATH); let resolc_arguments = &[&path, "--bin", ResolcOptSettings::PERFORMANCE]; let solc_arguments = &[ @@ -114,10 +116,10 @@ fn bench_large_div_rem(c: &mut Criterion) { } fn bench_memset(c: &mut Criterion) { - let mut group = group(c, "Memset (`--yul`)"); + let mut group = group(c, "Yul Memset"); group .sample_size(100) - .measurement_time(Duration::from_secs(7)); + .measurement_time(Duration::from_secs(8)); let path = absolute_path(YUL_MEMSET_CONTRACT_PATH); let resolc_arguments = &[&path, "--yul", "--bin", ResolcOptSettings::PERFORMANCE]; let solc_arguments = &[ @@ -133,10 +135,10 @@ fn bench_memset(c: &mut Criterion) { } fn bench_return(c: &mut Criterion) { - let mut group = group(c, "Return (`--yul`)"); + let mut group = group(c, "Yul Return"); group .sample_size(100) - .measurement_time(Duration::from_secs(6)); + .measurement_time(Duration::from_secs(7)); let path = absolute_path(YUL_RETURN_CONTRACT_PATH); let resolc_arguments = &[&path, "--yul", "--bin", ResolcOptSettings::PERFORMANCE]; let solc_arguments = &[ @@ -151,12 +153,39 @@ fn bench_return(c: &mut Criterion) { bench(group, resolc_arguments, solc_arguments, None); } -fn bench_standard_json_contracts(c: &mut Criterion) { - let mut group = group(c, "Multiple Contracts (`--standard-json`)"); +fn bench_standard_json_codegen_per_file(c: &mut Criterion) { + let mut group = group(c, "Std JSON Codegen All Files"); + group + .sample_size(10) + .measurement_time(Duration::from_secs(200)); + let path = absolute_path(STANDARD_JSON_PVM_CODEGEN_PER_FILE_PATH); + let resolc_arguments = &["--standard-json"]; + let solc_arguments = &["--standard-json"]; + + bench(group, resolc_arguments, solc_arguments, Some(&path)); +} + +/// Bytecode should only be generated for one of the requested files. +/// However, `solc` will compile in the same time as when requesting bytecode +/// for all contracts in all files, due to incorrectly generating bytecode for all. +fn bench_standard_json_codegen_one_file(c: &mut Criterion) { + let mut group = group(c, "Std JSON Codegen One of Many Files"); group .sample_size(20) - .measurement_time(Duration::from_secs(35)); - let path = absolute_path(STANDARD_JSON_CONTRACTS_PATH); + .measurement_time(Duration::from_secs(15)); + let path = absolute_path(STANDARD_JSON_PVM_CODEGEN_ONE_FILE_PATH); + let resolc_arguments = &["--standard-json"]; + let solc_arguments = &["--standard-json"]; + + bench(group, resolc_arguments, solc_arguments, Some(&path)); +} + +fn bench_standard_json_no_codegen_per_file(c: &mut Criterion) { + let mut group = group(c, "Std JSON No Codegen"); + group + .sample_size(20) + .measurement_time(Duration::from_secs(20)); + let path = absolute_path(STANDARD_JSON_NO_PVM_CODEGEN_PER_FILE_PATH); let resolc_arguments = &["--standard-json"]; let solc_arguments = &["--standard-json"]; @@ -172,6 +201,8 @@ criterion_group!( bench_large_div_rem, bench_memset, bench_return, - bench_standard_json_contracts, + bench_standard_json_codegen_per_file, + bench_standard_json_codegen_one_file, + bench_standard_json_no_codegen_per_file, ); criterion_main!(benches); diff --git a/crates/resolc/src/cli_utils.rs b/crates/resolc/src/cli_utils.rs index ae01434..c37a034 100644 --- a/crates/resolc/src/cli_utils.rs +++ b/crates/resolc/src/cli_utils.rs @@ -26,6 +26,8 @@ pub const YUL_RETURN_CONTRACT_PATH: &str = "src/tests/data/yul/return.yul"; /// The standard JSON contracts test fixture path. pub const STANDARD_JSON_CONTRACTS_PATH: &str = "src/tests/data/standard_json/solidity_contracts.json"; +/// The standard JSON contracts test fixture path that requests every single output. +pub const STANDARD_JSON_ALL_OUTPUTS_PATH: &str = "src/tests/data/standard_json/all_outputs.json"; /// The standard JSON no EVM codegen test fixture path. /// /// This contains EVM bytecode selection flags with provided code @@ -37,6 +39,41 @@ pub const STANDARD_JSON_NO_EVM_CODEGEN_PATH: &str = /// infamous "Stack too deep" error in the EVM codegen. pub const STANDARD_JSON_NO_EVM_CODEGEN_COMPLEX_PATH: &str = "src/tests/data/standard_json/no_evm_codegen_complex.json"; +/// The standard JSON PVM codegen all wildcard test fixture path. +/// +/// These contracts are similar to ones used in an example project. +pub const STANDARD_JSON_PVM_CODEGEN_ALL_WILDCARD_PATH: &str = + "src/tests/data/standard_json/pvm_codegen_all_wildcard.json"; +/// The standard JSON PVM codegen for all files on a per-file basis test fixture path. +/// +/// These contracts are similar to ones used in an example project. +pub const STANDARD_JSON_PVM_CODEGEN_PER_FILE_PATH: &str = + "src/tests/data/standard_json/pvm_codegen_per_file.json"; +/// The standard JSON PVM codegen for one out of many files test fixture path. +/// +/// These contracts are similar to ones used in an example project. +pub const STANDARD_JSON_PVM_CODEGEN_ONE_FILE_PATH: &str = + "src/tests/data/standard_json/pvm_codegen_one_file.json"; +/// The standard JSON no PVM codegen for any file on a per-file basis test fixture path. +/// +/// This omits `evm` bytecode selection flags, which should thereby +/// prevent PVM bytecode generation. +/// +/// These contracts are similar to ones used in an example project. +pub const STANDARD_JSON_NO_PVM_CODEGEN_PER_FILE_PATH: &str = + "src/tests/data/standard_json/no_pvm_codegen_per_file.json"; +/// The standard JSON Yul contract PVM codegen test fixture path. +/// +/// This requests the full `evm` output object, which should thereby +/// generate all `evm` child fields. +pub const STANDARD_JSON_YUL_PVM_CODEGEN_PATH: &str = + "src/tests/data/standard_json/yul_pvm_codegen.json"; +/// The standard JSON Yul contract no PVM codegen test fixture path. +/// +/// This omits `evm` bytecode selection flags, which should thereby prevent +/// PVM bytecode generation and only validate the Yul. +pub const STANDARD_JSON_YUL_NO_PVM_CODEGEN_PATH: &str = + "src/tests/data/standard_json/yul_no_pvm_codegen.json"; /// The `resolc` YUL mode flag. pub const RESOLC_YUL_FLAG: &str = "--yul"; diff --git a/crates/resolc/src/lib.rs b/crates/resolc/src/lib.rs index b488259..029b5aa 100644 --- a/crates/resolc/src/lib.rs +++ b/crates/resolc/src/lib.rs @@ -130,7 +130,7 @@ pub fn standard_output( input_files, libraries, remappings, - SolcStandardJsonInputSettingsSelection::new_required(), + SolcStandardJsonInputSettingsSelection::new_required_for_codegen_all(), SolcStandardJsonInputSettingsOptimizer::new( solc_optimizer_enabled, SolcStandardJsonInputSettingsOptimizer::default_mode(), @@ -210,8 +210,14 @@ pub fn standard_json( .polkavm .debug_information .unwrap_or(false); - solc_input.extend_selection(SolcStandardJsonInputSettingsSelection::new_required()); + + solc_input.extend_selection( + SolcStandardJsonInputSettingsSelection::new_required_for_codegen( + &solc_input.settings.output_selection, + ), + ); solc_input.retain_output_selection(); + let mut solc_output = solc.standard_json( &mut solc_input, messages, @@ -220,31 +226,19 @@ pub fn standard_json( allow_paths, )?; - let (mut solc_output, project) = match language { - SolcStandardJsonInputLanguage::Solidity => { - let project = Project::try_from_standard_json_output( - &mut solc_output, - solc_input.settings.libraries, - &solc_version, - &debug_config, - )?; - (solc_output, project) + if language == SolcStandardJsonInputLanguage::Yul { + let solc_output = solc.validate_yul_standard_json(&mut solc_input, messages)?; + if solc_output.has_errors() { + solc_output.write_and_exit(prune_output); } - SolcStandardJsonInputLanguage::Yul => { - let mut solc_output = solc.validate_yul_standard_json(&mut solc_input, messages)?; - if solc_output.has_errors() { - solc_output.write_and_exit(prune_output); - } - let project = Project::try_from_yul_sources( - solc_input.sources, - solc_input.settings.libraries, - Some(&mut solc_output), - &debug_config, - )?; + } - (solc_output, project) - } - }; + let project = Project::try_from_standard_json_output( + &mut solc_output, + solc_input.settings.libraries, + &solc_version, + &debug_config, + )?; if solc_output.has_errors() { solc_output.write_and_exit(prune_output); diff --git a/crates/resolc/src/tests/cli/standard_json.rs b/crates/resolc/src/tests/cli/standard_json.rs index fa98f3f..20c1993 100644 --- a/crates/resolc/src/tests/cli/standard_json.rs +++ b/crates/resolc/src/tests/cli/standard_json.rs @@ -1,17 +1,179 @@ //! The tests for running resolc with standard JSON option. use revive_solc_json_interface::{ - PolkaVMDefaultHeapMemorySize, PolkaVMDefaultStackMemorySize, SolcStandardJsonOutput, + PolkaVMDefaultHeapMemorySize, PolkaVMDefaultStackMemorySize, + SolcStandardJsonInputSettingsSelectionFileFlag, SolcStandardJsonOutput, }; use crate::cli_utils::{ assert_command_success, assert_equal_exit_codes, execute_resolc_with_stdin_input, - execute_solc_with_stdin_input, STANDARD_JSON_CONTRACTS_PATH, + execute_solc_with_stdin_input, STANDARD_JSON_ALL_OUTPUTS_PATH, STANDARD_JSON_CONTRACTS_PATH, STANDARD_JSON_NO_EVM_CODEGEN_COMPLEX_PATH, STANDARD_JSON_NO_EVM_CODEGEN_PATH, + STANDARD_JSON_NO_PVM_CODEGEN_PER_FILE_PATH, STANDARD_JSON_PVM_CODEGEN_ALL_WILDCARD_PATH, + STANDARD_JSON_PVM_CODEGEN_ONE_FILE_PATH, STANDARD_JSON_PVM_CODEGEN_PER_FILE_PATH, + STANDARD_JSON_YUL_NO_PVM_CODEGEN_PATH, STANDARD_JSON_YUL_PVM_CODEGEN_PATH, }; const JSON_OPTION: &str = "--standard-json"; +/// A subset of contracts and sources expected to exist in the JSON output. +struct ExpectedOutput { + contracts: Vec, + sources: Vec, +} + +/// A contract expected to exist in the JSON output. +struct ExpectedContract { + /// The file path. + path: &'static str, + /// The contract name. + name: &'static str, + /// All contract-level fields of the JSON output selection expected to exist, + /// such as `metadata`, `irOptimized`, etc. If `evm.bytecode` was requested, + /// both `evm` and `evm.bytecode` should be expected. + fields: Vec<&'static str>, +} + +/// A source expected to exist in the JSON output. +struct ExpectedSource { + /// The file path. + path: &'static str, + /// All file-level fields of the JSON output selection expected to exist, + /// such as `ast`, as well as the `id` field. + fields: Vec<&'static str>, +} + +/// Asserts that the `expected` subset of contracts and sources match the ones in the `actual` output. +/// If expected sources or contracts are empty, asserts that the respective actual output is also empty. +fn assert_output_matches(actual: &SolcStandardJsonOutput, expected: &ExpectedOutput) { + assert_sources_output_matches(actual, expected); + assert_contracts_output_matches(actual, expected); +} + +/// Asserts that the `expected` subset of sources match the ones in the `actual` output. +/// If expected sources is empty, asserts that the actual output is also empty. +fn assert_sources_output_matches(actual: &SolcStandardJsonOutput, expected: &ExpectedOutput) { + if expected.sources.is_empty() { + assert!(actual.sources.is_empty(), "sources should not be populated"); + return; + } + + assert!( + actual.sources.len() >= expected.sources.len(), + "at least {} sources should be populated", + expected.sources.len() + ); + + for expected_source in &expected.sources { + let actual_source = actual + .sources + .get(expected_source.path) + .unwrap_or_else(|| panic!("the file `{}` should exist", expected_source.path)); + let actual_source_json = serde_json::to_value(actual_source).unwrap(); + + // Verify that every expected output exists. + for field in &expected_source.fields { + assert!( + actual_source_json.get(field).is_some(), + "the `{field}` for the file `{}` should be generated", + expected_source.path + ); + } + + // Verify that every unexpected output is omitted. + let all_fields = &["id", "ast"]; + for field in all_fields { + if !expected_source.fields.contains(field) { + assert!( + actual_source_json.get(field).is_none(), + "the `{field}` for the file `{}` should not be generated", + expected_source.path + ); + } + } + } +} + +/// Asserts that the `expected` subset of contracts match the ones in the `actual` output. +/// If expected contracts is empty, asserts that the actual output is also empty. +fn assert_contracts_output_matches(actual: &SolcStandardJsonOutput, expected: &ExpectedOutput) { + if expected.contracts.is_empty() { + assert!( + actual.contracts.is_empty(), + "contracts should not be populated" + ); + return; + } + + assert!( + actual.contracts.len() >= expected.contracts.len(), + "at least {} contracts should be populated", + expected.contracts.len() + ); + + for expected_contract in &expected.contracts { + let actual_contract = actual + .contracts + .get(expected_contract.path) + .unwrap_or_else(|| panic!("the file `{}` should exist", expected_contract.path)) + .get(expected_contract.name) + .unwrap_or_else(|| { + panic!( + "the contract `{}` in file `{}` should exist", + expected_contract.name, expected_contract.path + ) + }); + let actual_contract_json = serde_json::to_value(actual_contract).unwrap(); + + // Verify that every expected output exists (e.g. `evm.bytecode`). + for field in &expected_contract.fields { + let mut parts = field.split('.'); + let (parent_field, child_field) = (parts.next().unwrap(), parts.next()); + let parent_output = actual_contract_json.get(parent_field); + + assert!( + parent_output.is_some(), + "the `{parent_field}` for the contract `{}` should be generated", + expected_contract.name, + ); + if let Some(child_field) = child_field { + assert!( + parent_output.unwrap().get(child_field).is_some(), + "the `{field}` for the contract `{}` should be generated", + expected_contract.name, + ); + } + } + + // Verify that every unexpected output is omitted. + for flag in SolcStandardJsonInputSettingsSelectionFileFlag::all() { + let field = serde_json::to_string(flag) + .unwrap() + .trim_matches('"') + .to_owned(); + if !expected_contract.fields.contains(&field.as_str()) { + let mut parts = field.split('.'); + let (parent_field, child_field) = (parts.next().unwrap(), parts.next()); + let parent_output = actual_contract_json.get(parent_field); + + if let Some(child_field) = child_field { + assert!( + parent_output.is_none_or(|p| p.get(child_field).is_none()), + "the `{field}` for the contract `{}` should not be generated", + expected_contract.name, + ); + } else { + assert!( + parent_output.is_none(), + "the `{parent_field}` for the contract `{}` should not be generated", + expected_contract.name, + ); + } + } + } + } +} + /// Asserts that the standard JSON output has at least one error with the given `error_message`. fn assert_standard_json_errors_contain(output: &SolcStandardJsonOutput, error_message: &str) { assert!( @@ -23,6 +185,11 @@ fn assert_standard_json_errors_contain(output: &SolcStandardJsonOutput, error_me ); } +/// Asserts that the standard JSON output has no errors with severity `error`. +fn assert_no_errors(output: &SolcStandardJsonOutput) { + assert!(!output.errors.iter().any(|error| error.is_error())); +} + /// Converts valid JSON text to `SolcStandardJsonOutput`. fn to_solc_standard_json_output(json_text: &str) -> SolcStandardJsonOutput { serde_json::from_str(json_text).unwrap() @@ -35,7 +202,7 @@ fn runs_with_valid_input_file() { assert_command_success(&resolc_result, "Providing a valid input file to stdin"); let resolc_output = to_solc_standard_json_output(&resolc_result.stdout); - assert!(!resolc_output.errors.iter().any(|error| error.is_error())); + assert_no_errors(&resolc_output); assert!( resolc_result.stdout.contains("contracts"), @@ -52,7 +219,7 @@ fn no_evm_codegen_requested() { assert_command_success(&result, "EVM codegen std json input fixture should build"); let output = to_solc_standard_json_output(&result.stdout); - assert!(!output.errors.iter().any(|msg| msg.severity == "error")) + assert_no_errors(&output); } /// A variant with more complex contracts. @@ -71,7 +238,229 @@ fn no_evm_codegen_requested_complex() { ); let output = to_solc_standard_json_output(&result.stdout); - assert!(!output.errors.iter().any(|msg| msg.severity == "error")) + assert_no_errors(&output); +} + +#[test] +fn all_outputs_requested() { + let result = execute_resolc_with_stdin_input(&[JSON_OPTION], STANDARD_JSON_ALL_OUTPUTS_PATH); + assert_command_success(&result, "the all output std JSON input fixture"); + + let output = to_solc_standard_json_output(&result.stdout); + assert_no_errors(&output); + + let expected_contract_fields = &[ + "abi", + "metadata", + "devdoc", + "userdoc", + "storageLayout", + "irOptimized", + "ir", + "evm", + "evm.methodIdentifiers", + "evm.bytecode", + "evm.deployedBytecode", + "evm.assembly", + ]; + let expected = ExpectedOutput { + contracts: vec![ + ExpectedContract { + path: "src/Counter.sol", + name: "Counter", + fields: expected_contract_fields.into(), + }, + ExpectedContract { + path: "script/Counter.s.sol", + name: "CounterScript", + fields: expected_contract_fields.into(), + }, + ExpectedContract { + path: "lib/forge-std/src/mocks/MockERC20.sol", + name: "MockERC20", + fields: expected_contract_fields.into(), + }, + ], + sources: vec![ + ExpectedSource { + path: "src/Counter.sol", + fields: vec!["id", "ast"], + }, + ExpectedSource { + path: "script/Counter.s.sol", + fields: vec!["id", "ast"], + }, + ExpectedSource { + path: "lib/forge-std/src/mocks/MockERC20.sol", + fields: vec!["id", "ast"], + }, + ], + }; + assert_output_matches(&output, &expected); +} + +#[test] +fn pvm_codegen_requested() { + let files = &[ + STANDARD_JSON_PVM_CODEGEN_ALL_WILDCARD_PATH, + STANDARD_JSON_PVM_CODEGEN_PER_FILE_PATH, + STANDARD_JSON_PVM_CODEGEN_ONE_FILE_PATH, + ]; + + for file in files { + let result = execute_resolc_with_stdin_input(&[JSON_OPTION], file); + assert_command_success(&result, &format!("the `{file}` input fixture")); + + let output = to_solc_standard_json_output(&result.stdout); + assert_no_errors(&output); + + let requests_codegen_for_one_file = *file == STANDARD_JSON_PVM_CODEGEN_ONE_FILE_PATH; + let expected_contract_fields_with_codegen = &[ + "abi", + "metadata", + "evm", + "evm.bytecode", + "evm.methodIdentifiers", + ]; + let expected_contract_fields_without_codegen = + &["abi", "metadata", "evm", "evm.methodIdentifiers"]; + + let expected = ExpectedOutput { + contracts: vec![ + ExpectedContract { + path: "src/common/GasService.sol", + name: "GasService", + // This is the contract expected to have codegen for all files tested here. + fields: expected_contract_fields_with_codegen.into(), + }, + ExpectedContract { + path: "src/common/Gateway.sol", + name: "Gateway", + fields: if requests_codegen_for_one_file { + expected_contract_fields_without_codegen.into() + } else { + expected_contract_fields_with_codegen.into() + }, + }, + ExpectedContract { + path: "src/common/MessageDispatcher.sol", + name: "MessageDispatcher", + fields: if requests_codegen_for_one_file { + expected_contract_fields_without_codegen.into() + } else { + expected_contract_fields_with_codegen.into() + }, + }, + ], + sources: vec![ + ExpectedSource { + path: "src/common/GasService.sol", + fields: vec!["id"], + }, + ExpectedSource { + path: "src/common/Gateway.sol", + fields: vec!["id"], + }, + ExpectedSource { + path: "src/common/MessageDispatcher.sol", + fields: vec!["id"], + }, + ], + }; + assert_output_matches(&output, &expected); + } +} + +#[test] +fn no_pvm_codegen_requested() { + let result = + execute_resolc_with_stdin_input(&[JSON_OPTION], STANDARD_JSON_NO_PVM_CODEGEN_PER_FILE_PATH); + assert_command_success( + &result, + "the no PVM codegen std JSON per file input fixture", + ); + + let output = to_solc_standard_json_output(&result.stdout); + assert_no_errors(&output); + + let expected = ExpectedOutput { + contracts: vec![ + ExpectedContract { + path: "src/common/GasService.sol", + name: "GasService", + fields: vec!["abi", "evm", "evm.methodIdentifiers", "metadata"], + }, + ExpectedContract { + path: "src/common/Gateway.sol", + name: "Gateway", + fields: vec!["abi", "evm", "evm.methodIdentifiers", "metadata"], + }, + ExpectedContract { + path: "src/common/MessageDispatcher.sol", + name: "MessageDispatcher", + fields: vec!["abi", "evm", "evm.methodIdentifiers", "metadata"], + }, + ], + sources: vec![ + ExpectedSource { + path: "src/common/GasService.sol", + fields: vec!["id"], + }, + ExpectedSource { + path: "src/common/Gateway.sol", + fields: vec!["id"], + }, + ExpectedSource { + path: "src/common/MessageDispatcher.sol", + fields: vec!["id"], + }, + ], + }; + assert_output_matches(&output, &expected); +} + +#[test] +fn yul_pvm_codegen_requested() { + let result = + execute_resolc_with_stdin_input(&[JSON_OPTION], STANDARD_JSON_YUL_PVM_CODEGEN_PATH); + assert_command_success(&result, "the PVM codegen from Yul std JSON input fixture"); + + let output = to_solc_standard_json_output(&result.stdout); + assert_no_errors(&output); + + let expected = ExpectedOutput { + contracts: vec![ExpectedContract { + path: "Test", + name: "Return", + fields: vec![ + "evm", + "evm.bytecode", + "evm.deployedBytecode", + "evm.assembly", + ], + }], + sources: vec![], + }; + assert_output_matches(&output, &expected); +} + +#[test] +fn yul_no_pvm_codegen_requested() { + let result = + execute_resolc_with_stdin_input(&[JSON_OPTION], STANDARD_JSON_YUL_NO_PVM_CODEGEN_PATH); + assert_command_success( + &result, + "the no PVM codegen from Yul std JSON input fixture", + ); + + let output = to_solc_standard_json_output(&result.stdout); + assert_no_errors(&output); + + let expected = ExpectedOutput { + contracts: vec![], + sources: vec![], + }; + assert_output_matches(&output, &expected); } #[test] diff --git a/crates/resolc/src/tests/data/standard_json/all_outputs.json b/crates/resolc/src/tests/data/standard_json/all_outputs.json new file mode 100644 index 0000000..2bc6b15 --- /dev/null +++ b/crates/resolc/src/tests/data/standard_json/all_outputs.json @@ -0,0 +1,115 @@ +{ + "language": "Solidity", + "sources": { + "lib/forge-std/src/Base.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.6.2 <0.9.0;\n\nimport {StdStorage} from \"./StdStorage.sol\";\nimport {Vm, VmSafe} from \"./Vm.sol\";\n\nabstract contract CommonBase {\n // Cheat code address, 0x7109709ECfa91a80626fF3989D68f67F5b1DD12D.\n address internal constant VM_ADDRESS = address(uint160(uint256(keccak256(\"hevm cheat code\"))));\n // console.sol and console2.sol work by executing a staticcall to this address.\n address internal constant CONSOLE = 0x000000000000000000636F6e736F6c652e6c6f67;\n // Used when deploying with create2, https://github.com/Arachnid/deterministic-deployment-proxy.\n address internal constant CREATE2_FACTORY = 0x4e59b44847b379578588920cA78FbF26c0B4956C;\n // Default address for tx.origin and msg.sender, 0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38.\n address internal constant DEFAULT_SENDER = address(uint160(uint256(keccak256(\"foundry default caller\"))));\n // Address of the test contract, deployed by the DEFAULT_SENDER.\n address internal constant DEFAULT_TEST_CONTRACT = 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f;\n // Deterministic deployment address of the Multicall3 contract.\n address internal constant MULTICALL3_ADDRESS = 0xcA11bde05977b3631167028862bE2a173976CA11;\n // The order of the secp256k1 curve.\n uint256 internal constant SECP256K1_ORDER =\n 115792089237316195423570985008687907852837564279074904382605163141518161494337;\n\n uint256 internal constant UINT256_MAX =\n 115792089237316195423570985008687907853269984665640564039457584007913129639935;\n\n Vm internal constant vm = Vm(VM_ADDRESS);\n StdStorage internal stdstore;\n}\n\nabstract contract TestBase is CommonBase {}\n\nabstract contract ScriptBase is CommonBase {\n VmSafe internal constant vmSafe = VmSafe(VM_ADDRESS);\n}\n" + }, + "lib/forge-std/src/Script.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.6.2 <0.9.0;\n\n// 💬 ABOUT\n// Forge Std's default Script.\n\n// 🧩 MODULES\nimport {console} from \"./console.sol\";\nimport {console2} from \"./console2.sol\";\nimport {safeconsole} from \"./safeconsole.sol\";\nimport {StdChains} from \"./StdChains.sol\";\nimport {StdCheatsSafe} from \"./StdCheats.sol\";\nimport {stdJson} from \"./StdJson.sol\";\nimport {stdMath} from \"./StdMath.sol\";\nimport {StdStorage, stdStorageSafe} from \"./StdStorage.sol\";\nimport {StdStyle} from \"./StdStyle.sol\";\nimport {StdUtils} from \"./StdUtils.sol\";\nimport {VmSafe} from \"./Vm.sol\";\n\n// 📦 BOILERPLATE\nimport {ScriptBase} from \"./Base.sol\";\n\n// ⭐️ SCRIPT\nabstract contract Script is ScriptBase, StdChains, StdCheatsSafe, StdUtils {\n // Note: IS_SCRIPT() must return true.\n bool public IS_SCRIPT = true;\n}\n" + }, + "lib/forge-std/src/StdAssertions.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.6.2 <0.9.0;\npragma experimental ABIEncoderV2;\n\nimport {Vm} from \"./Vm.sol\";\n\nabstract contract StdAssertions {\n Vm private constant vm = Vm(address(uint160(uint256(keccak256(\"hevm cheat code\")))));\n\n event log(string);\n event logs(bytes);\n\n event log_address(address);\n event log_bytes32(bytes32);\n event log_int(int256);\n event log_uint(uint256);\n event log_bytes(bytes);\n event log_string(string);\n\n event log_named_address(string key, address val);\n event log_named_bytes32(string key, bytes32 val);\n event log_named_decimal_int(string key, int256 val, uint256 decimals);\n event log_named_decimal_uint(string key, uint256 val, uint256 decimals);\n event log_named_int(string key, int256 val);\n event log_named_uint(string key, uint256 val);\n event log_named_bytes(string key, bytes val);\n event log_named_string(string key, string val);\n\n event log_array(uint256[] val);\n event log_array(int256[] val);\n event log_array(address[] val);\n event log_named_array(string key, uint256[] val);\n event log_named_array(string key, int256[] val);\n event log_named_array(string key, address[] val);\n\n bool private _failed;\n\n function failed() public view returns (bool) {\n if (_failed) {\n return _failed;\n } else {\n return vm.load(address(vm), bytes32(\"failed\")) != bytes32(0);\n }\n }\n\n function fail() internal virtual {\n vm.store(address(vm), bytes32(\"failed\"), bytes32(uint256(1)));\n _failed = true;\n }\n\n function assertTrue(bool data) internal pure virtual {\n vm.assertTrue(data);\n }\n\n function assertTrue(bool data, string memory err) internal pure virtual {\n vm.assertTrue(data, err);\n }\n\n function assertFalse(bool data) internal pure virtual {\n vm.assertFalse(data);\n }\n\n function assertFalse(bool data, string memory err) internal pure virtual {\n vm.assertFalse(data, err);\n }\n\n function assertEq(bool left, bool right) internal pure virtual {\n vm.assertEq(left, right);\n }\n\n function assertEq(bool left, bool right, string memory err) internal pure virtual {\n vm.assertEq(left, right, err);\n }\n\n function assertEq(uint256 left, uint256 right) internal pure virtual {\n vm.assertEq(left, right);\n }\n\n function assertEq(uint256 left, uint256 right, string memory err) internal pure virtual {\n vm.assertEq(left, right, err);\n }\n\n function assertEqDecimal(uint256 left, uint256 right, uint256 decimals) internal pure virtual {\n vm.assertEqDecimal(left, right, decimals);\n }\n\n function assertEqDecimal(uint256 left, uint256 right, uint256 decimals, string memory err) internal pure virtual {\n vm.assertEqDecimal(left, right, decimals, err);\n }\n\n function assertEq(int256 left, int256 right) internal pure virtual {\n vm.assertEq(left, right);\n }\n\n function assertEq(int256 left, int256 right, string memory err) internal pure virtual {\n vm.assertEq(left, right, err);\n }\n\n function assertEqDecimal(int256 left, int256 right, uint256 decimals) internal pure virtual {\n vm.assertEqDecimal(left, right, decimals);\n }\n\n function assertEqDecimal(int256 left, int256 right, uint256 decimals, string memory err) internal pure virtual {\n vm.assertEqDecimal(left, right, decimals, err);\n }\n\n function assertEq(address left, address right) internal pure virtual {\n vm.assertEq(left, right);\n }\n\n function assertEq(address left, address right, string memory err) internal pure virtual {\n vm.assertEq(left, right, err);\n }\n\n function assertEq(bytes32 left, bytes32 right) internal pure virtual {\n vm.assertEq(left, right);\n }\n\n function assertEq(bytes32 left, bytes32 right, string memory err) internal pure virtual {\n vm.assertEq(left, right, err);\n }\n\n function assertEq32(bytes32 left, bytes32 right) internal pure virtual {\n assertEq(left, right);\n }\n\n function assertEq32(bytes32 left, bytes32 right, string memory err) internal pure virtual {\n assertEq(left, right, err);\n }\n\n function assertEq(string memory left, string memory right) internal pure virtual {\n vm.assertEq(left, right);\n }\n\n function assertEq(string memory left, string memory right, string memory err) internal pure virtual {\n vm.assertEq(left, right, err);\n }\n\n function assertEq(bytes memory left, bytes memory right) internal pure virtual {\n vm.assertEq(left, right);\n }\n\n function assertEq(bytes memory left, bytes memory right, string memory err) internal pure virtual {\n vm.assertEq(left, right, err);\n }\n\n function assertEq(bool[] memory left, bool[] memory right) internal pure virtual {\n vm.assertEq(left, right);\n }\n\n function assertEq(bool[] memory left, bool[] memory right, string memory err) internal pure virtual {\n vm.assertEq(left, right, err);\n }\n\n function assertEq(uint256[] memory left, uint256[] memory right) internal pure virtual {\n vm.assertEq(left, right);\n }\n\n function assertEq(uint256[] memory left, uint256[] memory right, string memory err) internal pure virtual {\n vm.assertEq(left, right, err);\n }\n\n function assertEq(int256[] memory left, int256[] memory right) internal pure virtual {\n vm.assertEq(left, right);\n }\n\n function assertEq(int256[] memory left, int256[] memory right, string memory err) internal pure virtual {\n vm.assertEq(left, right, err);\n }\n\n function assertEq(address[] memory left, address[] memory right) internal pure virtual {\n vm.assertEq(left, right);\n }\n\n function assertEq(address[] memory left, address[] memory right, string memory err) internal pure virtual {\n vm.assertEq(left, right, err);\n }\n\n function assertEq(bytes32[] memory left, bytes32[] memory right) internal pure virtual {\n vm.assertEq(left, right);\n }\n\n function assertEq(bytes32[] memory left, bytes32[] memory right, string memory err) internal pure virtual {\n vm.assertEq(left, right, err);\n }\n\n function assertEq(string[] memory left, string[] memory right) internal pure virtual {\n vm.assertEq(left, right);\n }\n\n function assertEq(string[] memory left, string[] memory right, string memory err) internal pure virtual {\n vm.assertEq(left, right, err);\n }\n\n function assertEq(bytes[] memory left, bytes[] memory right) internal pure virtual {\n vm.assertEq(left, right);\n }\n\n function assertEq(bytes[] memory left, bytes[] memory right, string memory err) internal pure virtual {\n vm.assertEq(left, right, err);\n }\n\n // Legacy helper\n function assertEqUint(uint256 left, uint256 right) internal pure virtual {\n assertEq(left, right);\n }\n\n function assertNotEq(bool left, bool right) internal pure virtual {\n vm.assertNotEq(left, right);\n }\n\n function assertNotEq(bool left, bool right, string memory err) internal pure virtual {\n vm.assertNotEq(left, right, err);\n }\n\n function assertNotEq(uint256 left, uint256 right) internal pure virtual {\n vm.assertNotEq(left, right);\n }\n\n function assertNotEq(uint256 left, uint256 right, string memory err) internal pure virtual {\n vm.assertNotEq(left, right, err);\n }\n\n function assertNotEqDecimal(uint256 left, uint256 right, uint256 decimals) internal pure virtual {\n vm.assertNotEqDecimal(left, right, decimals);\n }\n\n function assertNotEqDecimal(uint256 left, uint256 right, uint256 decimals, string memory err)\n internal\n pure\n virtual\n {\n vm.assertNotEqDecimal(left, right, decimals, err);\n }\n\n function assertNotEq(int256 left, int256 right) internal pure virtual {\n vm.assertNotEq(left, right);\n }\n\n function assertNotEq(int256 left, int256 right, string memory err) internal pure virtual {\n vm.assertNotEq(left, right, err);\n }\n\n function assertNotEqDecimal(int256 left, int256 right, uint256 decimals) internal pure virtual {\n vm.assertNotEqDecimal(left, right, decimals);\n }\n\n function assertNotEqDecimal(int256 left, int256 right, uint256 decimals, string memory err) internal pure virtual {\n vm.assertNotEqDecimal(left, right, decimals, err);\n }\n\n function assertNotEq(address left, address right) internal pure virtual {\n vm.assertNotEq(left, right);\n }\n\n function assertNotEq(address left, address right, string memory err) internal pure virtual {\n vm.assertNotEq(left, right, err);\n }\n\n function assertNotEq(bytes32 left, bytes32 right) internal pure virtual {\n vm.assertNotEq(left, right);\n }\n\n function assertNotEq(bytes32 left, bytes32 right, string memory err) internal pure virtual {\n vm.assertNotEq(left, right, err);\n }\n\n function assertNotEq32(bytes32 left, bytes32 right) internal pure virtual {\n assertNotEq(left, right);\n }\n\n function assertNotEq32(bytes32 left, bytes32 right, string memory err) internal pure virtual {\n assertNotEq(left, right, err);\n }\n\n function assertNotEq(string memory left, string memory right) internal pure virtual {\n vm.assertNotEq(left, right);\n }\n\n function assertNotEq(string memory left, string memory right, string memory err) internal pure virtual {\n vm.assertNotEq(left, right, err);\n }\n\n function assertNotEq(bytes memory left, bytes memory right) internal pure virtual {\n vm.assertNotEq(left, right);\n }\n\n function assertNotEq(bytes memory left, bytes memory right, string memory err) internal pure virtual {\n vm.assertNotEq(left, right, err);\n }\n\n function assertNotEq(bool[] memory left, bool[] memory right) internal pure virtual {\n vm.assertNotEq(left, right);\n }\n\n function assertNotEq(bool[] memory left, bool[] memory right, string memory err) internal pure virtual {\n vm.assertNotEq(left, right, err);\n }\n\n function assertNotEq(uint256[] memory left, uint256[] memory right) internal pure virtual {\n vm.assertNotEq(left, right);\n }\n\n function assertNotEq(uint256[] memory left, uint256[] memory right, string memory err) internal pure virtual {\n vm.assertNotEq(left, right, err);\n }\n\n function assertNotEq(int256[] memory left, int256[] memory right) internal pure virtual {\n vm.assertNotEq(left, right);\n }\n\n function assertNotEq(int256[] memory left, int256[] memory right, string memory err) internal pure virtual {\n vm.assertNotEq(left, right, err);\n }\n\n function assertNotEq(address[] memory left, address[] memory right) internal pure virtual {\n vm.assertNotEq(left, right);\n }\n\n function assertNotEq(address[] memory left, address[] memory right, string memory err) internal pure virtual {\n vm.assertNotEq(left, right, err);\n }\n\n function assertNotEq(bytes32[] memory left, bytes32[] memory right) internal pure virtual {\n vm.assertNotEq(left, right);\n }\n\n function assertNotEq(bytes32[] memory left, bytes32[] memory right, string memory err) internal pure virtual {\n vm.assertNotEq(left, right, err);\n }\n\n function assertNotEq(string[] memory left, string[] memory right) internal pure virtual {\n vm.assertNotEq(left, right);\n }\n\n function assertNotEq(string[] memory left, string[] memory right, string memory err) internal pure virtual {\n vm.assertNotEq(left, right, err);\n }\n\n function assertNotEq(bytes[] memory left, bytes[] memory right) internal pure virtual {\n vm.assertNotEq(left, right);\n }\n\n function assertNotEq(bytes[] memory left, bytes[] memory right, string memory err) internal pure virtual {\n vm.assertNotEq(left, right, err);\n }\n\n function assertLt(uint256 left, uint256 right) internal pure virtual {\n vm.assertLt(left, right);\n }\n\n function assertLt(uint256 left, uint256 right, string memory err) internal pure virtual {\n vm.assertLt(left, right, err);\n }\n\n function assertLtDecimal(uint256 left, uint256 right, uint256 decimals) internal pure virtual {\n vm.assertLtDecimal(left, right, decimals);\n }\n\n function assertLtDecimal(uint256 left, uint256 right, uint256 decimals, string memory err) internal pure virtual {\n vm.assertLtDecimal(left, right, decimals, err);\n }\n\n function assertLt(int256 left, int256 right) internal pure virtual {\n vm.assertLt(left, right);\n }\n\n function assertLt(int256 left, int256 right, string memory err) internal pure virtual {\n vm.assertLt(left, right, err);\n }\n\n function assertLtDecimal(int256 left, int256 right, uint256 decimals) internal pure virtual {\n vm.assertLtDecimal(left, right, decimals);\n }\n\n function assertLtDecimal(int256 left, int256 right, uint256 decimals, string memory err) internal pure virtual {\n vm.assertLtDecimal(left, right, decimals, err);\n }\n\n function assertGt(uint256 left, uint256 right) internal pure virtual {\n vm.assertGt(left, right);\n }\n\n function assertGt(uint256 left, uint256 right, string memory err) internal pure virtual {\n vm.assertGt(left, right, err);\n }\n\n function assertGtDecimal(uint256 left, uint256 right, uint256 decimals) internal pure virtual {\n vm.assertGtDecimal(left, right, decimals);\n }\n\n function assertGtDecimal(uint256 left, uint256 right, uint256 decimals, string memory err) internal pure virtual {\n vm.assertGtDecimal(left, right, decimals, err);\n }\n\n function assertGt(int256 left, int256 right) internal pure virtual {\n vm.assertGt(left, right);\n }\n\n function assertGt(int256 left, int256 right, string memory err) internal pure virtual {\n vm.assertGt(left, right, err);\n }\n\n function assertGtDecimal(int256 left, int256 right, uint256 decimals) internal pure virtual {\n vm.assertGtDecimal(left, right, decimals);\n }\n\n function assertGtDecimal(int256 left, int256 right, uint256 decimals, string memory err) internal pure virtual {\n vm.assertGtDecimal(left, right, decimals, err);\n }\n\n function assertLe(uint256 left, uint256 right) internal pure virtual {\n vm.assertLe(left, right);\n }\n\n function assertLe(uint256 left, uint256 right, string memory err) internal pure virtual {\n vm.assertLe(left, right, err);\n }\n\n function assertLeDecimal(uint256 left, uint256 right, uint256 decimals) internal pure virtual {\n vm.assertLeDecimal(left, right, decimals);\n }\n\n function assertLeDecimal(uint256 left, uint256 right, uint256 decimals, string memory err) internal pure virtual {\n vm.assertLeDecimal(left, right, decimals, err);\n }\n\n function assertLe(int256 left, int256 right) internal pure virtual {\n vm.assertLe(left, right);\n }\n\n function assertLe(int256 left, int256 right, string memory err) internal pure virtual {\n vm.assertLe(left, right, err);\n }\n\n function assertLeDecimal(int256 left, int256 right, uint256 decimals) internal pure virtual {\n vm.assertLeDecimal(left, right, decimals);\n }\n\n function assertLeDecimal(int256 left, int256 right, uint256 decimals, string memory err) internal pure virtual {\n vm.assertLeDecimal(left, right, decimals, err);\n }\n\n function assertGe(uint256 left, uint256 right) internal pure virtual {\n vm.assertGe(left, right);\n }\n\n function assertGe(uint256 left, uint256 right, string memory err) internal pure virtual {\n vm.assertGe(left, right, err);\n }\n\n function assertGeDecimal(uint256 left, uint256 right, uint256 decimals) internal pure virtual {\n vm.assertGeDecimal(left, right, decimals);\n }\n\n function assertGeDecimal(uint256 left, uint256 right, uint256 decimals, string memory err) internal pure virtual {\n vm.assertGeDecimal(left, right, decimals, err);\n }\n\n function assertGe(int256 left, int256 right) internal pure virtual {\n vm.assertGe(left, right);\n }\n\n function assertGe(int256 left, int256 right, string memory err) internal pure virtual {\n vm.assertGe(left, right, err);\n }\n\n function assertGeDecimal(int256 left, int256 right, uint256 decimals) internal pure virtual {\n vm.assertGeDecimal(left, right, decimals);\n }\n\n function assertGeDecimal(int256 left, int256 right, uint256 decimals, string memory err) internal pure virtual {\n vm.assertGeDecimal(left, right, decimals, err);\n }\n\n function assertApproxEqAbs(uint256 left, uint256 right, uint256 maxDelta) internal pure virtual {\n vm.assertApproxEqAbs(left, right, maxDelta);\n }\n\n function assertApproxEqAbs(uint256 left, uint256 right, uint256 maxDelta, string memory err)\n internal\n pure\n virtual\n {\n vm.assertApproxEqAbs(left, right, maxDelta, err);\n }\n\n function assertApproxEqAbsDecimal(uint256 left, uint256 right, uint256 maxDelta, uint256 decimals)\n internal\n pure\n virtual\n {\n vm.assertApproxEqAbsDecimal(left, right, maxDelta, decimals);\n }\n\n function assertApproxEqAbsDecimal(\n uint256 left,\n uint256 right,\n uint256 maxDelta,\n uint256 decimals,\n string memory err\n ) internal pure virtual {\n vm.assertApproxEqAbsDecimal(left, right, maxDelta, decimals, err);\n }\n\n function assertApproxEqAbs(int256 left, int256 right, uint256 maxDelta) internal pure virtual {\n vm.assertApproxEqAbs(left, right, maxDelta);\n }\n\n function assertApproxEqAbs(int256 left, int256 right, uint256 maxDelta, string memory err) internal pure virtual {\n vm.assertApproxEqAbs(left, right, maxDelta, err);\n }\n\n function assertApproxEqAbsDecimal(int256 left, int256 right, uint256 maxDelta, uint256 decimals)\n internal\n pure\n virtual\n {\n vm.assertApproxEqAbsDecimal(left, right, maxDelta, decimals);\n }\n\n function assertApproxEqAbsDecimal(int256 left, int256 right, uint256 maxDelta, uint256 decimals, string memory err)\n internal\n pure\n virtual\n {\n vm.assertApproxEqAbsDecimal(left, right, maxDelta, decimals, err);\n }\n\n function assertApproxEqRel(\n uint256 left,\n uint256 right,\n uint256 maxPercentDelta // An 18 decimal fixed point number, where 1e18 == 100%\n ) internal pure virtual {\n vm.assertApproxEqRel(left, right, maxPercentDelta);\n }\n\n function assertApproxEqRel(\n uint256 left,\n uint256 right,\n uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100%\n string memory err\n ) internal pure virtual {\n vm.assertApproxEqRel(left, right, maxPercentDelta, err);\n }\n\n function assertApproxEqRelDecimal(\n uint256 left,\n uint256 right,\n uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100%\n uint256 decimals\n ) internal pure virtual {\n vm.assertApproxEqRelDecimal(left, right, maxPercentDelta, decimals);\n }\n\n function assertApproxEqRelDecimal(\n uint256 left,\n uint256 right,\n uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100%\n uint256 decimals,\n string memory err\n ) internal pure virtual {\n vm.assertApproxEqRelDecimal(left, right, maxPercentDelta, decimals, err);\n }\n\n function assertApproxEqRel(int256 left, int256 right, uint256 maxPercentDelta) internal pure virtual {\n vm.assertApproxEqRel(left, right, maxPercentDelta);\n }\n\n function assertApproxEqRel(\n int256 left,\n int256 right,\n uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100%\n string memory err\n ) internal pure virtual {\n vm.assertApproxEqRel(left, right, maxPercentDelta, err);\n }\n\n function assertApproxEqRelDecimal(\n int256 left,\n int256 right,\n uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100%\n uint256 decimals\n ) internal pure virtual {\n vm.assertApproxEqRelDecimal(left, right, maxPercentDelta, decimals);\n }\n\n function assertApproxEqRelDecimal(\n int256 left,\n int256 right,\n uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100%\n uint256 decimals,\n string memory err\n ) internal pure virtual {\n vm.assertApproxEqRelDecimal(left, right, maxPercentDelta, decimals, err);\n }\n\n // Inherited from DSTest, not used but kept for backwards-compatibility\n function checkEq0(bytes memory left, bytes memory right) internal pure returns (bool) {\n return keccak256(left) == keccak256(right);\n }\n\n function assertEq0(bytes memory left, bytes memory right) internal pure virtual {\n assertEq(left, right);\n }\n\n function assertEq0(bytes memory left, bytes memory right, string memory err) internal pure virtual {\n assertEq(left, right, err);\n }\n\n function assertNotEq0(bytes memory left, bytes memory right) internal pure virtual {\n assertNotEq(left, right);\n }\n\n function assertNotEq0(bytes memory left, bytes memory right, string memory err) internal pure virtual {\n assertNotEq(left, right, err);\n }\n\n function assertEqCall(address target, bytes memory callDataA, bytes memory callDataB) internal virtual {\n assertEqCall(target, callDataA, target, callDataB, true);\n }\n\n function assertEqCall(address targetA, bytes memory callDataA, address targetB, bytes memory callDataB)\n internal\n virtual\n {\n assertEqCall(targetA, callDataA, targetB, callDataB, true);\n }\n\n function assertEqCall(address target, bytes memory callDataA, bytes memory callDataB, bool strictRevertData)\n internal\n virtual\n {\n assertEqCall(target, callDataA, target, callDataB, strictRevertData);\n }\n\n function assertEqCall(\n address targetA,\n bytes memory callDataA,\n address targetB,\n bytes memory callDataB,\n bool strictRevertData\n ) internal virtual {\n (bool successA, bytes memory returnDataA) = address(targetA).call(callDataA);\n (bool successB, bytes memory returnDataB) = address(targetB).call(callDataB);\n\n if (successA && successB) {\n assertEq(returnDataA, returnDataB, \"Call return data does not match\");\n }\n\n if (!successA && !successB && strictRevertData) {\n assertEq(returnDataA, returnDataB, \"Call revert data does not match\");\n }\n\n if (!successA && successB) {\n emit log(\"Error: Calls were not equal\");\n emit log_named_bytes(\" Left call revert data\", returnDataA);\n emit log_named_bytes(\" Right call return data\", returnDataB);\n revert(\"assertion failed\");\n }\n\n if (successA && !successB) {\n emit log(\"Error: Calls were not equal\");\n emit log_named_bytes(\" Left call return data\", returnDataA);\n emit log_named_bytes(\" Right call revert data\", returnDataB);\n revert(\"assertion failed\");\n }\n }\n}\n" + }, + "lib/forge-std/src/StdChains.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.6.2 <0.9.0;\n\nimport {VmSafe} from \"./Vm.sol\";\n\n/**\n * StdChains provides information about EVM compatible chains that can be used in scripts/tests.\n * For each chain, the chain's name, chain ID, and a default RPC URL are provided. Chains are\n * identified by their alias, which is the same as the alias in the `[rpc_endpoints]` section of\n * the `foundry.toml` file. For best UX, ensure the alias in the `foundry.toml` file match the\n * alias used in this contract, which can be found as the first argument to the\n * `setChainWithDefaultRpcUrl` call in the `initializeStdChains` function.\n *\n * There are two main ways to use this contract:\n * 1. Set a chain with `setChain(string memory chainAlias, ChainData memory chain)` or\n * `setChain(string memory chainAlias, Chain memory chain)`\n * 2. Get a chain with `getChain(string memory chainAlias)` or `getChain(uint256 chainId)`.\n *\n * The first time either of those are used, chains are initialized with the default set of RPC URLs.\n * This is done in `initializeStdChains`, which uses `setChainWithDefaultRpcUrl`. Defaults are recorded in\n * `defaultRpcUrls`.\n *\n * The `setChain` function is straightforward, and it simply saves off the given chain data.\n *\n * The `getChain` methods use `getChainWithUpdatedRpcUrl` to return a chain. For example, let's say\n * we want to retrieve the RPC URL for `mainnet`:\n * - If you have specified data with `setChain`, it will return that.\n * - If you have configured a mainnet RPC URL in `foundry.toml`, it will return the URL, provided it\n * is valid (e.g. a URL is specified, or an environment variable is given and exists).\n * - If neither of the above conditions is met, the default data is returned.\n *\n * Summarizing the above, the prioritization hierarchy is `setChain` -> `foundry.toml` -> environment variable -> defaults.\n */\nabstract contract StdChains {\n VmSafe private constant vm = VmSafe(address(uint160(uint256(keccak256(\"hevm cheat code\")))));\n\n bool private stdChainsInitialized;\n\n struct ChainData {\n string name;\n uint256 chainId;\n string rpcUrl;\n }\n\n struct Chain {\n // The chain name.\n string name;\n // The chain's Chain ID.\n uint256 chainId;\n // The chain's alias. (i.e. what gets specified in `foundry.toml`).\n string chainAlias;\n // A default RPC endpoint for this chain.\n // NOTE: This default RPC URL is included for convenience to facilitate quick tests and\n // experimentation. Do not use this RPC URL for production test suites, CI, or other heavy\n // usage as you will be throttled and this is a disservice to others who need this endpoint.\n string rpcUrl;\n }\n\n // Maps from the chain's alias (matching the alias in the `foundry.toml` file) to chain data.\n mapping(string => Chain) private chains;\n // Maps from the chain's alias to it's default RPC URL.\n mapping(string => string) private defaultRpcUrls;\n // Maps from a chain ID to it's alias.\n mapping(uint256 => string) private idToAlias;\n\n bool private fallbackToDefaultRpcUrls = true;\n\n // The RPC URL will be fetched from config or defaultRpcUrls if possible.\n function getChain(string memory chainAlias) internal virtual returns (Chain memory chain) {\n require(bytes(chainAlias).length != 0, \"StdChains getChain(string): Chain alias cannot be the empty string.\");\n\n initializeStdChains();\n chain = chains[chainAlias];\n require(\n chain.chainId != 0,\n string(abi.encodePacked(\"StdChains getChain(string): Chain with alias \\\"\", chainAlias, \"\\\" not found.\"))\n );\n\n chain = getChainWithUpdatedRpcUrl(chainAlias, chain);\n }\n\n function getChain(uint256 chainId) internal virtual returns (Chain memory chain) {\n require(chainId != 0, \"StdChains getChain(uint256): Chain ID cannot be 0.\");\n initializeStdChains();\n string memory chainAlias = idToAlias[chainId];\n\n chain = chains[chainAlias];\n\n require(\n chain.chainId != 0,\n string(abi.encodePacked(\"StdChains getChain(uint256): Chain with ID \", vm.toString(chainId), \" not found.\"))\n );\n\n chain = getChainWithUpdatedRpcUrl(chainAlias, chain);\n }\n\n // set chain info, with priority to argument's rpcUrl field.\n function setChain(string memory chainAlias, ChainData memory chain) internal virtual {\n require(\n bytes(chainAlias).length != 0,\n \"StdChains setChain(string,ChainData): Chain alias cannot be the empty string.\"\n );\n\n require(chain.chainId != 0, \"StdChains setChain(string,ChainData): Chain ID cannot be 0.\");\n\n initializeStdChains();\n string memory foundAlias = idToAlias[chain.chainId];\n\n require(\n bytes(foundAlias).length == 0 || keccak256(bytes(foundAlias)) == keccak256(bytes(chainAlias)),\n string(\n abi.encodePacked(\n \"StdChains setChain(string,ChainData): Chain ID \",\n vm.toString(chain.chainId),\n \" already used by \\\"\",\n foundAlias,\n \"\\\".\"\n )\n )\n );\n\n uint256 oldChainId = chains[chainAlias].chainId;\n delete idToAlias[oldChainId];\n\n chains[chainAlias] =\n Chain({name: chain.name, chainId: chain.chainId, chainAlias: chainAlias, rpcUrl: chain.rpcUrl});\n idToAlias[chain.chainId] = chainAlias;\n }\n\n // set chain info, with priority to argument's rpcUrl field.\n function setChain(string memory chainAlias, Chain memory chain) internal virtual {\n setChain(chainAlias, ChainData({name: chain.name, chainId: chain.chainId, rpcUrl: chain.rpcUrl}));\n }\n\n function _toUpper(string memory str) private pure returns (string memory) {\n bytes memory strb = bytes(str);\n bytes memory copy = new bytes(strb.length);\n for (uint256 i = 0; i < strb.length; i++) {\n bytes1 b = strb[i];\n if (b >= 0x61 && b <= 0x7A) {\n copy[i] = bytes1(uint8(b) - 32);\n } else {\n copy[i] = b;\n }\n }\n return string(copy);\n }\n\n // lookup rpcUrl, in descending order of priority:\n // current -> config (foundry.toml) -> environment variable -> default\n function getChainWithUpdatedRpcUrl(string memory chainAlias, Chain memory chain)\n private\n view\n returns (Chain memory)\n {\n if (bytes(chain.rpcUrl).length == 0) {\n try vm.rpcUrl(chainAlias) returns (string memory configRpcUrl) {\n chain.rpcUrl = configRpcUrl;\n } catch (bytes memory err) {\n string memory envName = string(abi.encodePacked(_toUpper(chainAlias), \"_RPC_URL\"));\n if (fallbackToDefaultRpcUrls) {\n chain.rpcUrl = vm.envOr(envName, defaultRpcUrls[chainAlias]);\n } else {\n chain.rpcUrl = vm.envString(envName);\n }\n // Distinguish 'not found' from 'cannot read'\n // The upstream error thrown by forge for failing cheats changed so we check both the old and new versions\n bytes memory oldNotFoundError =\n abi.encodeWithSignature(\"CheatCodeError\", string(abi.encodePacked(\"invalid rpc url \", chainAlias)));\n bytes memory newNotFoundError = abi.encodeWithSignature(\n \"CheatcodeError(string)\", string(abi.encodePacked(\"invalid rpc url: \", chainAlias))\n );\n bytes32 errHash = keccak256(err);\n if (\n (errHash != keccak256(oldNotFoundError) && errHash != keccak256(newNotFoundError))\n || bytes(chain.rpcUrl).length == 0\n ) {\n /// @solidity memory-safe-assembly\n assembly {\n revert(add(32, err), mload(err))\n }\n }\n }\n }\n return chain;\n }\n\n function setFallbackToDefaultRpcUrls(bool useDefault) internal {\n fallbackToDefaultRpcUrls = useDefault;\n }\n\n function initializeStdChains() private {\n if (stdChainsInitialized) return;\n\n stdChainsInitialized = true;\n\n // If adding an RPC here, make sure to test the default RPC URL in `test_Rpcs` in `StdChains.t.sol`\n setChainWithDefaultRpcUrl(\"anvil\", ChainData(\"Anvil\", 31337, \"http://127.0.0.1:8545\"));\n setChainWithDefaultRpcUrl(\n \"mainnet\", ChainData(\"Mainnet\", 1, \"https://eth-mainnet.alchemyapi.io/v2/pwc5rmJhrdoaSEfimoKEmsvOjKSmPDrP\")\n );\n setChainWithDefaultRpcUrl(\n \"sepolia\", ChainData(\"Sepolia\", 11155111, \"https://sepolia.infura.io/v3/b9794ad1ddf84dfb8c34d6bb5dca2001\")\n );\n setChainWithDefaultRpcUrl(\"holesky\", ChainData(\"Holesky\", 17000, \"https://rpc.holesky.ethpandaops.io\"));\n setChainWithDefaultRpcUrl(\"optimism\", ChainData(\"Optimism\", 10, \"https://mainnet.optimism.io\"));\n setChainWithDefaultRpcUrl(\n \"optimism_sepolia\", ChainData(\"Optimism Sepolia\", 11155420, \"https://sepolia.optimism.io\")\n );\n setChainWithDefaultRpcUrl(\"arbitrum_one\", ChainData(\"Arbitrum One\", 42161, \"https://arb1.arbitrum.io/rpc\"));\n setChainWithDefaultRpcUrl(\n \"arbitrum_one_sepolia\", ChainData(\"Arbitrum One Sepolia\", 421614, \"https://sepolia-rollup.arbitrum.io/rpc\")\n );\n setChainWithDefaultRpcUrl(\"arbitrum_nova\", ChainData(\"Arbitrum Nova\", 42170, \"https://nova.arbitrum.io/rpc\"));\n setChainWithDefaultRpcUrl(\"polygon\", ChainData(\"Polygon\", 137, \"https://polygon-rpc.com\"));\n setChainWithDefaultRpcUrl(\n \"polygon_amoy\", ChainData(\"Polygon Amoy\", 80002, \"https://rpc-amoy.polygon.technology\")\n );\n setChainWithDefaultRpcUrl(\"avalanche\", ChainData(\"Avalanche\", 43114, \"https://api.avax.network/ext/bc/C/rpc\"));\n setChainWithDefaultRpcUrl(\n \"avalanche_fuji\", ChainData(\"Avalanche Fuji\", 43113, \"https://api.avax-test.network/ext/bc/C/rpc\")\n );\n setChainWithDefaultRpcUrl(\n \"bnb_smart_chain\", ChainData(\"BNB Smart Chain\", 56, \"https://bsc-dataseed1.binance.org\")\n );\n setChainWithDefaultRpcUrl(\n \"bnb_smart_chain_testnet\",\n ChainData(\"BNB Smart Chain Testnet\", 97, \"https://rpc.ankr.com/bsc_testnet_chapel\")\n );\n setChainWithDefaultRpcUrl(\"gnosis_chain\", ChainData(\"Gnosis Chain\", 100, \"https://rpc.gnosischain.com\"));\n setChainWithDefaultRpcUrl(\"moonbeam\", ChainData(\"Moonbeam\", 1284, \"https://rpc.api.moonbeam.network\"));\n setChainWithDefaultRpcUrl(\n \"moonriver\", ChainData(\"Moonriver\", 1285, \"https://rpc.api.moonriver.moonbeam.network\")\n );\n setChainWithDefaultRpcUrl(\"moonbase\", ChainData(\"Moonbase\", 1287, \"https://rpc.testnet.moonbeam.network\"));\n setChainWithDefaultRpcUrl(\"base_sepolia\", ChainData(\"Base Sepolia\", 84532, \"https://sepolia.base.org\"));\n setChainWithDefaultRpcUrl(\"base\", ChainData(\"Base\", 8453, \"https://mainnet.base.org\"));\n setChainWithDefaultRpcUrl(\"blast_sepolia\", ChainData(\"Blast Sepolia\", 168587773, \"https://sepolia.blast.io\"));\n setChainWithDefaultRpcUrl(\"blast\", ChainData(\"Blast\", 81457, \"https://rpc.blast.io\"));\n setChainWithDefaultRpcUrl(\"fantom_opera\", ChainData(\"Fantom Opera\", 250, \"https://rpc.ankr.com/fantom/\"));\n setChainWithDefaultRpcUrl(\n \"fantom_opera_testnet\", ChainData(\"Fantom Opera Testnet\", 4002, \"https://rpc.ankr.com/fantom_testnet/\")\n );\n setChainWithDefaultRpcUrl(\"fraxtal\", ChainData(\"Fraxtal\", 252, \"https://rpc.frax.com\"));\n setChainWithDefaultRpcUrl(\"fraxtal_testnet\", ChainData(\"Fraxtal Testnet\", 2522, \"https://rpc.testnet.frax.com\"));\n setChainWithDefaultRpcUrl(\n \"berachain_bartio_testnet\", ChainData(\"Berachain bArtio Testnet\", 80084, \"https://bartio.rpc.berachain.com\")\n );\n setChainWithDefaultRpcUrl(\"flare\", ChainData(\"Flare\", 14, \"https://flare-api.flare.network/ext/C/rpc\"));\n setChainWithDefaultRpcUrl(\n \"flare_coston2\", ChainData(\"Flare Coston2\", 114, \"https://coston2-api.flare.network/ext/C/rpc\")\n );\n }\n\n // set chain info, with priority to chainAlias' rpc url in foundry.toml\n function setChainWithDefaultRpcUrl(string memory chainAlias, ChainData memory chain) private {\n string memory rpcUrl = chain.rpcUrl;\n defaultRpcUrls[chainAlias] = rpcUrl;\n chain.rpcUrl = \"\";\n setChain(chainAlias, chain);\n chain.rpcUrl = rpcUrl; // restore argument\n }\n}\n" + }, + "lib/forge-std/src/StdCheats.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.6.2 <0.9.0;\n\npragma experimental ABIEncoderV2;\n\nimport {StdStorage, stdStorage} from \"./StdStorage.sol\";\nimport {console2} from \"./console2.sol\";\nimport {Vm} from \"./Vm.sol\";\n\nabstract contract StdCheatsSafe {\n Vm private constant vm = Vm(address(uint160(uint256(keccak256(\"hevm cheat code\")))));\n\n uint256 private constant UINT256_MAX =\n 115792089237316195423570985008687907853269984665640564039457584007913129639935;\n\n bool private gasMeteringOff;\n\n // Data structures to parse Transaction objects from the broadcast artifact\n // that conform to EIP1559. The Raw structs is what is parsed from the JSON\n // and then converted to the one that is used by the user for better UX.\n\n struct RawTx1559 {\n string[] arguments;\n address contractAddress;\n string contractName;\n // json value name = function\n string functionSig;\n bytes32 hash;\n // json value name = tx\n RawTx1559Detail txDetail;\n // json value name = type\n string opcode;\n }\n\n struct RawTx1559Detail {\n AccessList[] accessList;\n bytes data;\n address from;\n bytes gas;\n bytes nonce;\n address to;\n bytes txType;\n bytes value;\n }\n\n struct Tx1559 {\n string[] arguments;\n address contractAddress;\n string contractName;\n string functionSig;\n bytes32 hash;\n Tx1559Detail txDetail;\n string opcode;\n }\n\n struct Tx1559Detail {\n AccessList[] accessList;\n bytes data;\n address from;\n uint256 gas;\n uint256 nonce;\n address to;\n uint256 txType;\n uint256 value;\n }\n\n // Data structures to parse Transaction objects from the broadcast artifact\n // that DO NOT conform to EIP1559. The Raw structs is what is parsed from the JSON\n // and then converted to the one that is used by the user for better UX.\n\n struct TxLegacy {\n string[] arguments;\n address contractAddress;\n string contractName;\n string functionSig;\n string hash;\n string opcode;\n TxDetailLegacy transaction;\n }\n\n struct TxDetailLegacy {\n AccessList[] accessList;\n uint256 chainId;\n bytes data;\n address from;\n uint256 gas;\n uint256 gasPrice;\n bytes32 hash;\n uint256 nonce;\n bytes1 opcode;\n bytes32 r;\n bytes32 s;\n uint256 txType;\n address to;\n uint8 v;\n uint256 value;\n }\n\n struct AccessList {\n address accessAddress;\n bytes32[] storageKeys;\n }\n\n // Data structures to parse Receipt objects from the broadcast artifact.\n // The Raw structs is what is parsed from the JSON\n // and then converted to the one that is used by the user for better UX.\n\n struct RawReceipt {\n bytes32 blockHash;\n bytes blockNumber;\n address contractAddress;\n bytes cumulativeGasUsed;\n bytes effectiveGasPrice;\n address from;\n bytes gasUsed;\n RawReceiptLog[] logs;\n bytes logsBloom;\n bytes status;\n address to;\n bytes32 transactionHash;\n bytes transactionIndex;\n }\n\n struct Receipt {\n bytes32 blockHash;\n uint256 blockNumber;\n address contractAddress;\n uint256 cumulativeGasUsed;\n uint256 effectiveGasPrice;\n address from;\n uint256 gasUsed;\n ReceiptLog[] logs;\n bytes logsBloom;\n uint256 status;\n address to;\n bytes32 transactionHash;\n uint256 transactionIndex;\n }\n\n // Data structures to parse the entire broadcast artifact, assuming the\n // transactions conform to EIP1559.\n\n struct EIP1559ScriptArtifact {\n string[] libraries;\n string path;\n string[] pending;\n Receipt[] receipts;\n uint256 timestamp;\n Tx1559[] transactions;\n TxReturn[] txReturns;\n }\n\n struct RawEIP1559ScriptArtifact {\n string[] libraries;\n string path;\n string[] pending;\n RawReceipt[] receipts;\n TxReturn[] txReturns;\n uint256 timestamp;\n RawTx1559[] transactions;\n }\n\n struct RawReceiptLog {\n // json value = address\n address logAddress;\n bytes32 blockHash;\n bytes blockNumber;\n bytes data;\n bytes logIndex;\n bool removed;\n bytes32[] topics;\n bytes32 transactionHash;\n bytes transactionIndex;\n bytes transactionLogIndex;\n }\n\n struct ReceiptLog {\n // json value = address\n address logAddress;\n bytes32 blockHash;\n uint256 blockNumber;\n bytes data;\n uint256 logIndex;\n bytes32[] topics;\n uint256 transactionIndex;\n uint256 transactionLogIndex;\n bool removed;\n }\n\n struct TxReturn {\n string internalType;\n string value;\n }\n\n struct Account {\n address addr;\n uint256 key;\n }\n\n enum AddressType {\n Payable,\n NonPayable,\n ZeroAddress,\n Precompile,\n ForgeAddress\n }\n\n // Checks that `addr` is not blacklisted by token contracts that have a blacklist.\n function assumeNotBlacklisted(address token, address addr) internal view virtual {\n // Nothing to check if `token` is not a contract.\n uint256 tokenCodeSize;\n assembly {\n tokenCodeSize := extcodesize(token)\n }\n require(tokenCodeSize > 0, \"StdCheats assumeNotBlacklisted(address,address): Token address is not a contract.\");\n\n bool success;\n bytes memory returnData;\n\n // 4-byte selector for `isBlacklisted(address)`, used by USDC.\n (success, returnData) = token.staticcall(abi.encodeWithSelector(0xfe575a87, addr));\n vm.assume(!success || abi.decode(returnData, (bool)) == false);\n\n // 4-byte selector for `isBlackListed(address)`, used by USDT.\n (success, returnData) = token.staticcall(abi.encodeWithSelector(0xe47d6060, addr));\n vm.assume(!success || abi.decode(returnData, (bool)) == false);\n }\n\n // Checks that `addr` is not blacklisted by token contracts that have a blacklist.\n // This is identical to `assumeNotBlacklisted(address,address)` but with a different name, for\n // backwards compatibility, since this name was used in the original PR which already has\n // a release. This function can be removed in a future release once we want a breaking change.\n function assumeNoBlacklisted(address token, address addr) internal view virtual {\n assumeNotBlacklisted(token, addr);\n }\n\n function assumeAddressIsNot(address addr, AddressType addressType) internal virtual {\n if (addressType == AddressType.Payable) {\n assumeNotPayable(addr);\n } else if (addressType == AddressType.NonPayable) {\n assumePayable(addr);\n } else if (addressType == AddressType.ZeroAddress) {\n assumeNotZeroAddress(addr);\n } else if (addressType == AddressType.Precompile) {\n assumeNotPrecompile(addr);\n } else if (addressType == AddressType.ForgeAddress) {\n assumeNotForgeAddress(addr);\n }\n }\n\n function assumeAddressIsNot(address addr, AddressType addressType1, AddressType addressType2) internal virtual {\n assumeAddressIsNot(addr, addressType1);\n assumeAddressIsNot(addr, addressType2);\n }\n\n function assumeAddressIsNot(\n address addr,\n AddressType addressType1,\n AddressType addressType2,\n AddressType addressType3\n ) internal virtual {\n assumeAddressIsNot(addr, addressType1);\n assumeAddressIsNot(addr, addressType2);\n assumeAddressIsNot(addr, addressType3);\n }\n\n function assumeAddressIsNot(\n address addr,\n AddressType addressType1,\n AddressType addressType2,\n AddressType addressType3,\n AddressType addressType4\n ) internal virtual {\n assumeAddressIsNot(addr, addressType1);\n assumeAddressIsNot(addr, addressType2);\n assumeAddressIsNot(addr, addressType3);\n assumeAddressIsNot(addr, addressType4);\n }\n\n // This function checks whether an address, `addr`, is payable. It works by sending 1 wei to\n // `addr` and checking the `success` return value.\n // NOTE: This function may result in state changes depending on the fallback/receive logic\n // implemented by `addr`, which should be taken into account when this function is used.\n function _isPayable(address addr) private returns (bool) {\n require(\n addr.balance < UINT256_MAX,\n \"StdCheats _isPayable(address): Balance equals max uint256, so it cannot receive any more funds\"\n );\n uint256 origBalanceTest = address(this).balance;\n uint256 origBalanceAddr = address(addr).balance;\n\n vm.deal(address(this), 1);\n (bool success,) = payable(addr).call{value: 1}(\"\");\n\n // reset balances\n vm.deal(address(this), origBalanceTest);\n vm.deal(addr, origBalanceAddr);\n\n return success;\n }\n\n // NOTE: This function may result in state changes depending on the fallback/receive logic\n // implemented by `addr`, which should be taken into account when this function is used. See the\n // `_isPayable` method for more information.\n function assumePayable(address addr) internal virtual {\n vm.assume(_isPayable(addr));\n }\n\n function assumeNotPayable(address addr) internal virtual {\n vm.assume(!_isPayable(addr));\n }\n\n function assumeNotZeroAddress(address addr) internal pure virtual {\n vm.assume(addr != address(0));\n }\n\n function assumeNotPrecompile(address addr) internal pure virtual {\n assumeNotPrecompile(addr, _pureChainId());\n }\n\n function assumeNotPrecompile(address addr, uint256 chainId) internal pure virtual {\n // Note: For some chains like Optimism these are technically predeploys (i.e. bytecode placed at a specific\n // address), but the same rationale for excluding them applies so we include those too.\n\n // These are reserved by Ethereum and may be on all EVM-compatible chains.\n vm.assume(addr < address(0x1) || addr > address(0xff));\n\n // forgefmt: disable-start\n if (chainId == 10 || chainId == 420) {\n // https://github.com/ethereum-optimism/optimism/blob/eaa371a0184b56b7ca6d9eb9cb0a2b78b2ccd864/op-bindings/predeploys/addresses.go#L6-L21\n vm.assume(addr < address(0x4200000000000000000000000000000000000000) || addr > address(0x4200000000000000000000000000000000000800));\n } else if (chainId == 42161 || chainId == 421613) {\n // https://developer.arbitrum.io/useful-addresses#arbitrum-precompiles-l2-same-on-all-arb-chains\n vm.assume(addr < address(0x0000000000000000000000000000000000000064) || addr > address(0x0000000000000000000000000000000000000068));\n } else if (chainId == 43114 || chainId == 43113) {\n // https://github.com/ava-labs/subnet-evm/blob/47c03fd007ecaa6de2c52ea081596e0a88401f58/precompile/params.go#L18-L59\n vm.assume(addr < address(0x0100000000000000000000000000000000000000) || addr > address(0x01000000000000000000000000000000000000ff));\n vm.assume(addr < address(0x0200000000000000000000000000000000000000) || addr > address(0x02000000000000000000000000000000000000FF));\n vm.assume(addr < address(0x0300000000000000000000000000000000000000) || addr > address(0x03000000000000000000000000000000000000Ff));\n }\n // forgefmt: disable-end\n }\n\n function assumeNotForgeAddress(address addr) internal pure virtual {\n // vm, console, and Create2Deployer addresses\n vm.assume(\n addr != address(vm) && addr != 0x000000000000000000636F6e736F6c652e6c6f67\n && addr != 0x4e59b44847b379578588920cA78FbF26c0B4956C\n );\n }\n\n function readEIP1559ScriptArtifact(string memory path)\n internal\n view\n virtual\n returns (EIP1559ScriptArtifact memory)\n {\n string memory data = vm.readFile(path);\n bytes memory parsedData = vm.parseJson(data);\n RawEIP1559ScriptArtifact memory rawArtifact = abi.decode(parsedData, (RawEIP1559ScriptArtifact));\n EIP1559ScriptArtifact memory artifact;\n artifact.libraries = rawArtifact.libraries;\n artifact.path = rawArtifact.path;\n artifact.timestamp = rawArtifact.timestamp;\n artifact.pending = rawArtifact.pending;\n artifact.txReturns = rawArtifact.txReturns;\n artifact.receipts = rawToConvertedReceipts(rawArtifact.receipts);\n artifact.transactions = rawToConvertedEIPTx1559s(rawArtifact.transactions);\n return artifact;\n }\n\n function rawToConvertedEIPTx1559s(RawTx1559[] memory rawTxs) internal pure virtual returns (Tx1559[] memory) {\n Tx1559[] memory txs = new Tx1559[](rawTxs.length);\n for (uint256 i; i < rawTxs.length; i++) {\n txs[i] = rawToConvertedEIPTx1559(rawTxs[i]);\n }\n return txs;\n }\n\n function rawToConvertedEIPTx1559(RawTx1559 memory rawTx) internal pure virtual returns (Tx1559 memory) {\n Tx1559 memory transaction;\n transaction.arguments = rawTx.arguments;\n transaction.contractName = rawTx.contractName;\n transaction.functionSig = rawTx.functionSig;\n transaction.hash = rawTx.hash;\n transaction.txDetail = rawToConvertedEIP1559Detail(rawTx.txDetail);\n transaction.opcode = rawTx.opcode;\n return transaction;\n }\n\n function rawToConvertedEIP1559Detail(RawTx1559Detail memory rawDetail)\n internal\n pure\n virtual\n returns (Tx1559Detail memory)\n {\n Tx1559Detail memory txDetail;\n txDetail.data = rawDetail.data;\n txDetail.from = rawDetail.from;\n txDetail.to = rawDetail.to;\n txDetail.nonce = _bytesToUint(rawDetail.nonce);\n txDetail.txType = _bytesToUint(rawDetail.txType);\n txDetail.value = _bytesToUint(rawDetail.value);\n txDetail.gas = _bytesToUint(rawDetail.gas);\n txDetail.accessList = rawDetail.accessList;\n return txDetail;\n }\n\n function readTx1559s(string memory path) internal view virtual returns (Tx1559[] memory) {\n string memory deployData = vm.readFile(path);\n bytes memory parsedDeployData = vm.parseJson(deployData, \".transactions\");\n RawTx1559[] memory rawTxs = abi.decode(parsedDeployData, (RawTx1559[]));\n return rawToConvertedEIPTx1559s(rawTxs);\n }\n\n function readTx1559(string memory path, uint256 index) internal view virtual returns (Tx1559 memory) {\n string memory deployData = vm.readFile(path);\n string memory key = string(abi.encodePacked(\".transactions[\", vm.toString(index), \"]\"));\n bytes memory parsedDeployData = vm.parseJson(deployData, key);\n RawTx1559 memory rawTx = abi.decode(parsedDeployData, (RawTx1559));\n return rawToConvertedEIPTx1559(rawTx);\n }\n\n // Analogous to readTransactions, but for receipts.\n function readReceipts(string memory path) internal view virtual returns (Receipt[] memory) {\n string memory deployData = vm.readFile(path);\n bytes memory parsedDeployData = vm.parseJson(deployData, \".receipts\");\n RawReceipt[] memory rawReceipts = abi.decode(parsedDeployData, (RawReceipt[]));\n return rawToConvertedReceipts(rawReceipts);\n }\n\n function readReceipt(string memory path, uint256 index) internal view virtual returns (Receipt memory) {\n string memory deployData = vm.readFile(path);\n string memory key = string(abi.encodePacked(\".receipts[\", vm.toString(index), \"]\"));\n bytes memory parsedDeployData = vm.parseJson(deployData, key);\n RawReceipt memory rawReceipt = abi.decode(parsedDeployData, (RawReceipt));\n return rawToConvertedReceipt(rawReceipt);\n }\n\n function rawToConvertedReceipts(RawReceipt[] memory rawReceipts) internal pure virtual returns (Receipt[] memory) {\n Receipt[] memory receipts = new Receipt[](rawReceipts.length);\n for (uint256 i; i < rawReceipts.length; i++) {\n receipts[i] = rawToConvertedReceipt(rawReceipts[i]);\n }\n return receipts;\n }\n\n function rawToConvertedReceipt(RawReceipt memory rawReceipt) internal pure virtual returns (Receipt memory) {\n Receipt memory receipt;\n receipt.blockHash = rawReceipt.blockHash;\n receipt.to = rawReceipt.to;\n receipt.from = rawReceipt.from;\n receipt.contractAddress = rawReceipt.contractAddress;\n receipt.effectiveGasPrice = _bytesToUint(rawReceipt.effectiveGasPrice);\n receipt.cumulativeGasUsed = _bytesToUint(rawReceipt.cumulativeGasUsed);\n receipt.gasUsed = _bytesToUint(rawReceipt.gasUsed);\n receipt.status = _bytesToUint(rawReceipt.status);\n receipt.transactionIndex = _bytesToUint(rawReceipt.transactionIndex);\n receipt.blockNumber = _bytesToUint(rawReceipt.blockNumber);\n receipt.logs = rawToConvertedReceiptLogs(rawReceipt.logs);\n receipt.logsBloom = rawReceipt.logsBloom;\n receipt.transactionHash = rawReceipt.transactionHash;\n return receipt;\n }\n\n function rawToConvertedReceiptLogs(RawReceiptLog[] memory rawLogs)\n internal\n pure\n virtual\n returns (ReceiptLog[] memory)\n {\n ReceiptLog[] memory logs = new ReceiptLog[](rawLogs.length);\n for (uint256 i; i < rawLogs.length; i++) {\n logs[i].logAddress = rawLogs[i].logAddress;\n logs[i].blockHash = rawLogs[i].blockHash;\n logs[i].blockNumber = _bytesToUint(rawLogs[i].blockNumber);\n logs[i].data = rawLogs[i].data;\n logs[i].logIndex = _bytesToUint(rawLogs[i].logIndex);\n logs[i].topics = rawLogs[i].topics;\n logs[i].transactionIndex = _bytesToUint(rawLogs[i].transactionIndex);\n logs[i].transactionLogIndex = _bytesToUint(rawLogs[i].transactionLogIndex);\n logs[i].removed = rawLogs[i].removed;\n }\n return logs;\n }\n\n // Deploy a contract by fetching the contract bytecode from\n // the artifacts directory\n // e.g. `deployCode(code, abi.encode(arg1,arg2,arg3))`\n function deployCode(string memory what, bytes memory args) internal virtual returns (address addr) {\n bytes memory bytecode = abi.encodePacked(vm.getCode(what), args);\n /// @solidity memory-safe-assembly\n assembly {\n addr := create(0, add(bytecode, 0x20), mload(bytecode))\n }\n\n require(addr != address(0), \"StdCheats deployCode(string,bytes): Deployment failed.\");\n }\n\n function deployCode(string memory what) internal virtual returns (address addr) {\n bytes memory bytecode = vm.getCode(what);\n /// @solidity memory-safe-assembly\n assembly {\n addr := create(0, add(bytecode, 0x20), mload(bytecode))\n }\n\n require(addr != address(0), \"StdCheats deployCode(string): Deployment failed.\");\n }\n\n /// @dev deploy contract with value on construction\n function deployCode(string memory what, bytes memory args, uint256 val) internal virtual returns (address addr) {\n bytes memory bytecode = abi.encodePacked(vm.getCode(what), args);\n /// @solidity memory-safe-assembly\n assembly {\n addr := create(val, add(bytecode, 0x20), mload(bytecode))\n }\n\n require(addr != address(0), \"StdCheats deployCode(string,bytes,uint256): Deployment failed.\");\n }\n\n function deployCode(string memory what, uint256 val) internal virtual returns (address addr) {\n bytes memory bytecode = vm.getCode(what);\n /// @solidity memory-safe-assembly\n assembly {\n addr := create(val, add(bytecode, 0x20), mload(bytecode))\n }\n\n require(addr != address(0), \"StdCheats deployCode(string,uint256): Deployment failed.\");\n }\n\n // creates a labeled address and the corresponding private key\n function makeAddrAndKey(string memory name) internal virtual returns (address addr, uint256 privateKey) {\n privateKey = uint256(keccak256(abi.encodePacked(name)));\n addr = vm.addr(privateKey);\n vm.label(addr, name);\n }\n\n // creates a labeled address\n function makeAddr(string memory name) internal virtual returns (address addr) {\n (addr,) = makeAddrAndKey(name);\n }\n\n // Destroys an account immediately, sending the balance to beneficiary.\n // Destroying means: balance will be zero, code will be empty, and nonce will be 0\n // This is similar to selfdestruct but not identical: selfdestruct destroys code and nonce\n // only after tx ends, this will run immediately.\n function destroyAccount(address who, address beneficiary) internal virtual {\n uint256 currBalance = who.balance;\n vm.etch(who, abi.encode());\n vm.deal(who, 0);\n vm.resetNonce(who);\n\n uint256 beneficiaryBalance = beneficiary.balance;\n vm.deal(beneficiary, currBalance + beneficiaryBalance);\n }\n\n // creates a struct containing both a labeled address and the corresponding private key\n function makeAccount(string memory name) internal virtual returns (Account memory account) {\n (account.addr, account.key) = makeAddrAndKey(name);\n }\n\n function deriveRememberKey(string memory mnemonic, uint32 index)\n internal\n virtual\n returns (address who, uint256 privateKey)\n {\n privateKey = vm.deriveKey(mnemonic, index);\n who = vm.rememberKey(privateKey);\n }\n\n function _bytesToUint(bytes memory b) private pure returns (uint256) {\n require(b.length <= 32, \"StdCheats _bytesToUint(bytes): Bytes length exceeds 32.\");\n return abi.decode(abi.encodePacked(new bytes(32 - b.length), b), (uint256));\n }\n\n function isFork() internal view virtual returns (bool status) {\n try vm.activeFork() {\n status = true;\n } catch (bytes memory) {}\n }\n\n modifier skipWhenForking() {\n if (!isFork()) {\n _;\n }\n }\n\n modifier skipWhenNotForking() {\n if (isFork()) {\n _;\n }\n }\n\n modifier noGasMetering() {\n vm.pauseGasMetering();\n // To prevent turning gas monitoring back on with nested functions that use this modifier,\n // we check if gasMetering started in the off position. If it did, we don't want to turn\n // it back on until we exit the top level function that used the modifier\n //\n // i.e. funcA() noGasMetering { funcB() }, where funcB has noGasMetering as well.\n // funcA will have `gasStartedOff` as false, funcB will have it as true,\n // so we only turn metering back on at the end of the funcA\n bool gasStartedOff = gasMeteringOff;\n gasMeteringOff = true;\n\n _;\n\n // if gas metering was on when this modifier was called, turn it back on at the end\n if (!gasStartedOff) {\n gasMeteringOff = false;\n vm.resumeGasMetering();\n }\n }\n\n // We use this complex approach of `_viewChainId` and `_pureChainId` to ensure there are no\n // compiler warnings when accessing chain ID in any solidity version supported by forge-std. We\n // can't simply access the chain ID in a normal view or pure function because the solc View Pure\n // Checker changed `chainid` from pure to view in 0.8.0.\n function _viewChainId() private view returns (uint256 chainId) {\n // Assembly required since `block.chainid` was introduced in 0.8.0.\n assembly {\n chainId := chainid()\n }\n\n address(this); // Silence warnings in older Solc versions.\n }\n\n function _pureChainId() private pure returns (uint256 chainId) {\n function() internal view returns (uint256) fnIn = _viewChainId;\n function() internal pure returns (uint256) pureChainId;\n assembly {\n pureChainId := fnIn\n }\n chainId = pureChainId();\n }\n}\n\n// Wrappers around cheatcodes to avoid footguns\nabstract contract StdCheats is StdCheatsSafe {\n using stdStorage for StdStorage;\n\n StdStorage private stdstore;\n Vm private constant vm = Vm(address(uint160(uint256(keccak256(\"hevm cheat code\")))));\n address private constant CONSOLE2_ADDRESS = 0x000000000000000000636F6e736F6c652e6c6f67;\n\n // Skip forward or rewind time by the specified number of seconds\n function skip(uint256 time) internal virtual {\n vm.warp(vm.getBlockTimestamp() + time);\n }\n\n function rewind(uint256 time) internal virtual {\n vm.warp(vm.getBlockTimestamp() - time);\n }\n\n // Setup a prank from an address that has some ether\n function hoax(address msgSender) internal virtual {\n vm.deal(msgSender, 1 << 128);\n vm.prank(msgSender);\n }\n\n function hoax(address msgSender, uint256 give) internal virtual {\n vm.deal(msgSender, give);\n vm.prank(msgSender);\n }\n\n function hoax(address msgSender, address origin) internal virtual {\n vm.deal(msgSender, 1 << 128);\n vm.prank(msgSender, origin);\n }\n\n function hoax(address msgSender, address origin, uint256 give) internal virtual {\n vm.deal(msgSender, give);\n vm.prank(msgSender, origin);\n }\n\n // Start perpetual prank from an address that has some ether\n function startHoax(address msgSender) internal virtual {\n vm.deal(msgSender, 1 << 128);\n vm.startPrank(msgSender);\n }\n\n function startHoax(address msgSender, uint256 give) internal virtual {\n vm.deal(msgSender, give);\n vm.startPrank(msgSender);\n }\n\n // Start perpetual prank from an address that has some ether\n // tx.origin is set to the origin parameter\n function startHoax(address msgSender, address origin) internal virtual {\n vm.deal(msgSender, 1 << 128);\n vm.startPrank(msgSender, origin);\n }\n\n function startHoax(address msgSender, address origin, uint256 give) internal virtual {\n vm.deal(msgSender, give);\n vm.startPrank(msgSender, origin);\n }\n\n function changePrank(address msgSender) internal virtual {\n console2_log_StdCheats(\"changePrank is deprecated. Please use vm.startPrank instead.\");\n vm.stopPrank();\n vm.startPrank(msgSender);\n }\n\n function changePrank(address msgSender, address txOrigin) internal virtual {\n vm.stopPrank();\n vm.startPrank(msgSender, txOrigin);\n }\n\n // The same as Vm's `deal`\n // Use the alternative signature for ERC20 tokens\n function deal(address to, uint256 give) internal virtual {\n vm.deal(to, give);\n }\n\n // Set the balance of an account for any ERC20 token\n // Use the alternative signature to update `totalSupply`\n function deal(address token, address to, uint256 give) internal virtual {\n deal(token, to, give, false);\n }\n\n // Set the balance of an account for any ERC1155 token\n // Use the alternative signature to update `totalSupply`\n function dealERC1155(address token, address to, uint256 id, uint256 give) internal virtual {\n dealERC1155(token, to, id, give, false);\n }\n\n function deal(address token, address to, uint256 give, bool adjust) internal virtual {\n // get current balance\n (, bytes memory balData) = token.staticcall(abi.encodeWithSelector(0x70a08231, to));\n uint256 prevBal = abi.decode(balData, (uint256));\n\n // update balance\n stdstore.target(token).sig(0x70a08231).with_key(to).checked_write(give);\n\n // update total supply\n if (adjust) {\n (, bytes memory totSupData) = token.staticcall(abi.encodeWithSelector(0x18160ddd));\n uint256 totSup = abi.decode(totSupData, (uint256));\n if (give < prevBal) {\n totSup -= (prevBal - give);\n } else {\n totSup += (give - prevBal);\n }\n stdstore.target(token).sig(0x18160ddd).checked_write(totSup);\n }\n }\n\n function dealERC1155(address token, address to, uint256 id, uint256 give, bool adjust) internal virtual {\n // get current balance\n (, bytes memory balData) = token.staticcall(abi.encodeWithSelector(0x00fdd58e, to, id));\n uint256 prevBal = abi.decode(balData, (uint256));\n\n // update balance\n stdstore.target(token).sig(0x00fdd58e).with_key(to).with_key(id).checked_write(give);\n\n // update total supply\n if (adjust) {\n (, bytes memory totSupData) = token.staticcall(abi.encodeWithSelector(0xbd85b039, id));\n require(\n totSupData.length != 0,\n \"StdCheats deal(address,address,uint,uint,bool): target contract is not ERC1155Supply.\"\n );\n uint256 totSup = abi.decode(totSupData, (uint256));\n if (give < prevBal) {\n totSup -= (prevBal - give);\n } else {\n totSup += (give - prevBal);\n }\n stdstore.target(token).sig(0xbd85b039).with_key(id).checked_write(totSup);\n }\n }\n\n function dealERC721(address token, address to, uint256 id) internal virtual {\n // check if token id is already minted and the actual owner.\n (bool successMinted, bytes memory ownerData) = token.staticcall(abi.encodeWithSelector(0x6352211e, id));\n require(successMinted, \"StdCheats deal(address,address,uint,bool): id not minted.\");\n\n // get owner current balance\n (, bytes memory fromBalData) =\n token.staticcall(abi.encodeWithSelector(0x70a08231, abi.decode(ownerData, (address))));\n uint256 fromPrevBal = abi.decode(fromBalData, (uint256));\n\n // get new user current balance\n (, bytes memory toBalData) = token.staticcall(abi.encodeWithSelector(0x70a08231, to));\n uint256 toPrevBal = abi.decode(toBalData, (uint256));\n\n // update balances\n stdstore.target(token).sig(0x70a08231).with_key(abi.decode(ownerData, (address))).checked_write(--fromPrevBal);\n stdstore.target(token).sig(0x70a08231).with_key(to).checked_write(++toPrevBal);\n\n // update owner\n stdstore.target(token).sig(0x6352211e).with_key(id).checked_write(to);\n }\n\n function deployCodeTo(string memory what, address where) internal virtual {\n deployCodeTo(what, \"\", 0, where);\n }\n\n function deployCodeTo(string memory what, bytes memory args, address where) internal virtual {\n deployCodeTo(what, args, 0, where);\n }\n\n function deployCodeTo(string memory what, bytes memory args, uint256 value, address where) internal virtual {\n bytes memory creationCode = vm.getCode(what);\n vm.etch(where, abi.encodePacked(creationCode, args));\n (bool success, bytes memory runtimeBytecode) = where.call{value: value}(\"\");\n require(success, \"StdCheats deployCodeTo(string,bytes,uint256,address): Failed to create runtime bytecode.\");\n vm.etch(where, runtimeBytecode);\n }\n\n // Used to prevent the compilation of console, which shortens the compilation time when console is not used elsewhere.\n function console2_log_StdCheats(string memory p0) private view {\n (bool status,) = address(CONSOLE2_ADDRESS).staticcall(abi.encodeWithSignature(\"log(string)\", p0));\n status;\n }\n}\n" + }, + "lib/forge-std/src/StdError.sol": { + "content": "// SPDX-License-Identifier: MIT\n// Panics work for versions >=0.8.0, but we lowered the pragma to make this compatible with Test\npragma solidity >=0.6.2 <0.9.0;\n\nlibrary stdError {\n bytes public constant assertionError = abi.encodeWithSignature(\"Panic(uint256)\", 0x01);\n bytes public constant arithmeticError = abi.encodeWithSignature(\"Panic(uint256)\", 0x11);\n bytes public constant divisionError = abi.encodeWithSignature(\"Panic(uint256)\", 0x12);\n bytes public constant enumConversionError = abi.encodeWithSignature(\"Panic(uint256)\", 0x21);\n bytes public constant encodeStorageError = abi.encodeWithSignature(\"Panic(uint256)\", 0x22);\n bytes public constant popError = abi.encodeWithSignature(\"Panic(uint256)\", 0x31);\n bytes public constant indexOOBError = abi.encodeWithSignature(\"Panic(uint256)\", 0x32);\n bytes public constant memOverflowError = abi.encodeWithSignature(\"Panic(uint256)\", 0x41);\n bytes public constant zeroVarError = abi.encodeWithSignature(\"Panic(uint256)\", 0x51);\n}\n" + }, + "lib/forge-std/src/StdInvariant.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.6.2 <0.9.0;\n\npragma experimental ABIEncoderV2;\n\nabstract contract StdInvariant {\n struct FuzzSelector {\n address addr;\n bytes4[] selectors;\n }\n\n struct FuzzArtifactSelector {\n string artifact;\n bytes4[] selectors;\n }\n\n struct FuzzInterface {\n address addr;\n string[] artifacts;\n }\n\n address[] private _excludedContracts;\n address[] private _excludedSenders;\n address[] private _targetedContracts;\n address[] private _targetedSenders;\n\n string[] private _excludedArtifacts;\n string[] private _targetedArtifacts;\n\n FuzzArtifactSelector[] private _targetedArtifactSelectors;\n\n FuzzSelector[] private _excludedSelectors;\n FuzzSelector[] private _targetedSelectors;\n\n FuzzInterface[] private _targetedInterfaces;\n\n // Functions for users:\n // These are intended to be called in tests.\n\n function excludeContract(address newExcludedContract_) internal {\n _excludedContracts.push(newExcludedContract_);\n }\n\n function excludeSelector(FuzzSelector memory newExcludedSelector_) internal {\n _excludedSelectors.push(newExcludedSelector_);\n }\n\n function excludeSender(address newExcludedSender_) internal {\n _excludedSenders.push(newExcludedSender_);\n }\n\n function excludeArtifact(string memory newExcludedArtifact_) internal {\n _excludedArtifacts.push(newExcludedArtifact_);\n }\n\n function targetArtifact(string memory newTargetedArtifact_) internal {\n _targetedArtifacts.push(newTargetedArtifact_);\n }\n\n function targetArtifactSelector(FuzzArtifactSelector memory newTargetedArtifactSelector_) internal {\n _targetedArtifactSelectors.push(newTargetedArtifactSelector_);\n }\n\n function targetContract(address newTargetedContract_) internal {\n _targetedContracts.push(newTargetedContract_);\n }\n\n function targetSelector(FuzzSelector memory newTargetedSelector_) internal {\n _targetedSelectors.push(newTargetedSelector_);\n }\n\n function targetSender(address newTargetedSender_) internal {\n _targetedSenders.push(newTargetedSender_);\n }\n\n function targetInterface(FuzzInterface memory newTargetedInterface_) internal {\n _targetedInterfaces.push(newTargetedInterface_);\n }\n\n // Functions for forge:\n // These are called by forge to run invariant tests and don't need to be called in tests.\n\n function excludeArtifacts() public view returns (string[] memory excludedArtifacts_) {\n excludedArtifacts_ = _excludedArtifacts;\n }\n\n function excludeContracts() public view returns (address[] memory excludedContracts_) {\n excludedContracts_ = _excludedContracts;\n }\n\n function excludeSelectors() public view returns (FuzzSelector[] memory excludedSelectors_) {\n excludedSelectors_ = _excludedSelectors;\n }\n\n function excludeSenders() public view returns (address[] memory excludedSenders_) {\n excludedSenders_ = _excludedSenders;\n }\n\n function targetArtifacts() public view returns (string[] memory targetedArtifacts_) {\n targetedArtifacts_ = _targetedArtifacts;\n }\n\n function targetArtifactSelectors() public view returns (FuzzArtifactSelector[] memory targetedArtifactSelectors_) {\n targetedArtifactSelectors_ = _targetedArtifactSelectors;\n }\n\n function targetContracts() public view returns (address[] memory targetedContracts_) {\n targetedContracts_ = _targetedContracts;\n }\n\n function targetSelectors() public view returns (FuzzSelector[] memory targetedSelectors_) {\n targetedSelectors_ = _targetedSelectors;\n }\n\n function targetSenders() public view returns (address[] memory targetedSenders_) {\n targetedSenders_ = _targetedSenders;\n }\n\n function targetInterfaces() public view returns (FuzzInterface[] memory targetedInterfaces_) {\n targetedInterfaces_ = _targetedInterfaces;\n }\n}\n" + }, + "lib/forge-std/src/StdJson.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.6.0 <0.9.0;\n\npragma experimental ABIEncoderV2;\n\nimport {VmSafe} from \"./Vm.sol\";\n\n// Helpers for parsing and writing JSON files\n// To parse:\n// ```\n// using stdJson for string;\n// string memory json = vm.readFile(\"\");\n// json.readUint(\"\");\n// ```\n// To write:\n// ```\n// using stdJson for string;\n// string memory json = \"json\";\n// json.serialize(\"a\", uint256(123));\n// string memory semiFinal = json.serialize(\"b\", string(\"test\"));\n// string memory finalJson = json.serialize(\"c\", semiFinal);\n// finalJson.write(\"\");\n// ```\n\nlibrary stdJson {\n VmSafe private constant vm = VmSafe(address(uint160(uint256(keccak256(\"hevm cheat code\")))));\n\n function keyExists(string memory json, string memory key) internal view returns (bool) {\n return vm.keyExistsJson(json, key);\n }\n\n function parseRaw(string memory json, string memory key) internal pure returns (bytes memory) {\n return vm.parseJson(json, key);\n }\n\n function readUint(string memory json, string memory key) internal pure returns (uint256) {\n return vm.parseJsonUint(json, key);\n }\n\n function readUintArray(string memory json, string memory key) internal pure returns (uint256[] memory) {\n return vm.parseJsonUintArray(json, key);\n }\n\n function readInt(string memory json, string memory key) internal pure returns (int256) {\n return vm.parseJsonInt(json, key);\n }\n\n function readIntArray(string memory json, string memory key) internal pure returns (int256[] memory) {\n return vm.parseJsonIntArray(json, key);\n }\n\n function readBytes32(string memory json, string memory key) internal pure returns (bytes32) {\n return vm.parseJsonBytes32(json, key);\n }\n\n function readBytes32Array(string memory json, string memory key) internal pure returns (bytes32[] memory) {\n return vm.parseJsonBytes32Array(json, key);\n }\n\n function readString(string memory json, string memory key) internal pure returns (string memory) {\n return vm.parseJsonString(json, key);\n }\n\n function readStringArray(string memory json, string memory key) internal pure returns (string[] memory) {\n return vm.parseJsonStringArray(json, key);\n }\n\n function readAddress(string memory json, string memory key) internal pure returns (address) {\n return vm.parseJsonAddress(json, key);\n }\n\n function readAddressArray(string memory json, string memory key) internal pure returns (address[] memory) {\n return vm.parseJsonAddressArray(json, key);\n }\n\n function readBool(string memory json, string memory key) internal pure returns (bool) {\n return vm.parseJsonBool(json, key);\n }\n\n function readBoolArray(string memory json, string memory key) internal pure returns (bool[] memory) {\n return vm.parseJsonBoolArray(json, key);\n }\n\n function readBytes(string memory json, string memory key) internal pure returns (bytes memory) {\n return vm.parseJsonBytes(json, key);\n }\n\n function readBytesArray(string memory json, string memory key) internal pure returns (bytes[] memory) {\n return vm.parseJsonBytesArray(json, key);\n }\n\n function readUintOr(string memory json, string memory key, uint256 defaultValue) internal view returns (uint256) {\n return keyExists(json, key) ? readUint(json, key) : defaultValue;\n }\n\n function readUintArrayOr(string memory json, string memory key, uint256[] memory defaultValue)\n internal\n view\n returns (uint256[] memory)\n {\n return keyExists(json, key) ? readUintArray(json, key) : defaultValue;\n }\n\n function readIntOr(string memory json, string memory key, int256 defaultValue) internal view returns (int256) {\n return keyExists(json, key) ? readInt(json, key) : defaultValue;\n }\n\n function readIntArrayOr(string memory json, string memory key, int256[] memory defaultValue)\n internal\n view\n returns (int256[] memory)\n {\n return keyExists(json, key) ? readIntArray(json, key) : defaultValue;\n }\n\n function readBytes32Or(string memory json, string memory key, bytes32 defaultValue)\n internal\n view\n returns (bytes32)\n {\n return keyExists(json, key) ? readBytes32(json, key) : defaultValue;\n }\n\n function readBytes32ArrayOr(string memory json, string memory key, bytes32[] memory defaultValue)\n internal\n view\n returns (bytes32[] memory)\n {\n return keyExists(json, key) ? readBytes32Array(json, key) : defaultValue;\n }\n\n function readStringOr(string memory json, string memory key, string memory defaultValue)\n internal\n view\n returns (string memory)\n {\n return keyExists(json, key) ? readString(json, key) : defaultValue;\n }\n\n function readStringArrayOr(string memory json, string memory key, string[] memory defaultValue)\n internal\n view\n returns (string[] memory)\n {\n return keyExists(json, key) ? readStringArray(json, key) : defaultValue;\n }\n\n function readAddressOr(string memory json, string memory key, address defaultValue)\n internal\n view\n returns (address)\n {\n return keyExists(json, key) ? readAddress(json, key) : defaultValue;\n }\n\n function readAddressArrayOr(string memory json, string memory key, address[] memory defaultValue)\n internal\n view\n returns (address[] memory)\n {\n return keyExists(json, key) ? readAddressArray(json, key) : defaultValue;\n }\n\n function readBoolOr(string memory json, string memory key, bool defaultValue) internal view returns (bool) {\n return keyExists(json, key) ? readBool(json, key) : defaultValue;\n }\n\n function readBoolArrayOr(string memory json, string memory key, bool[] memory defaultValue)\n internal\n view\n returns (bool[] memory)\n {\n return keyExists(json, key) ? readBoolArray(json, key) : defaultValue;\n }\n\n function readBytesOr(string memory json, string memory key, bytes memory defaultValue)\n internal\n view\n returns (bytes memory)\n {\n return keyExists(json, key) ? readBytes(json, key) : defaultValue;\n }\n\n function readBytesArrayOr(string memory json, string memory key, bytes[] memory defaultValue)\n internal\n view\n returns (bytes[] memory)\n {\n return keyExists(json, key) ? readBytesArray(json, key) : defaultValue;\n }\n\n function serialize(string memory jsonKey, string memory rootObject) internal returns (string memory) {\n return vm.serializeJson(jsonKey, rootObject);\n }\n\n function serialize(string memory jsonKey, string memory key, bool value) internal returns (string memory) {\n return vm.serializeBool(jsonKey, key, value);\n }\n\n function serialize(string memory jsonKey, string memory key, bool[] memory value)\n internal\n returns (string memory)\n {\n return vm.serializeBool(jsonKey, key, value);\n }\n\n function serialize(string memory jsonKey, string memory key, uint256 value) internal returns (string memory) {\n return vm.serializeUint(jsonKey, key, value);\n }\n\n function serialize(string memory jsonKey, string memory key, uint256[] memory value)\n internal\n returns (string memory)\n {\n return vm.serializeUint(jsonKey, key, value);\n }\n\n function serialize(string memory jsonKey, string memory key, int256 value) internal returns (string memory) {\n return vm.serializeInt(jsonKey, key, value);\n }\n\n function serialize(string memory jsonKey, string memory key, int256[] memory value)\n internal\n returns (string memory)\n {\n return vm.serializeInt(jsonKey, key, value);\n }\n\n function serialize(string memory jsonKey, string memory key, address value) internal returns (string memory) {\n return vm.serializeAddress(jsonKey, key, value);\n }\n\n function serialize(string memory jsonKey, string memory key, address[] memory value)\n internal\n returns (string memory)\n {\n return vm.serializeAddress(jsonKey, key, value);\n }\n\n function serialize(string memory jsonKey, string memory key, bytes32 value) internal returns (string memory) {\n return vm.serializeBytes32(jsonKey, key, value);\n }\n\n function serialize(string memory jsonKey, string memory key, bytes32[] memory value)\n internal\n returns (string memory)\n {\n return vm.serializeBytes32(jsonKey, key, value);\n }\n\n function serialize(string memory jsonKey, string memory key, bytes memory value) internal returns (string memory) {\n return vm.serializeBytes(jsonKey, key, value);\n }\n\n function serialize(string memory jsonKey, string memory key, bytes[] memory value)\n internal\n returns (string memory)\n {\n return vm.serializeBytes(jsonKey, key, value);\n }\n\n function serialize(string memory jsonKey, string memory key, string memory value)\n internal\n returns (string memory)\n {\n return vm.serializeString(jsonKey, key, value);\n }\n\n function serialize(string memory jsonKey, string memory key, string[] memory value)\n internal\n returns (string memory)\n {\n return vm.serializeString(jsonKey, key, value);\n }\n\n function write(string memory jsonKey, string memory path) internal {\n vm.writeJson(jsonKey, path);\n }\n\n function write(string memory jsonKey, string memory path, string memory valueKey) internal {\n vm.writeJson(jsonKey, path, valueKey);\n }\n}\n" + }, + "lib/forge-std/src/StdMath.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.6.2 <0.9.0;\n\nlibrary stdMath {\n int256 private constant INT256_MIN = -57896044618658097711785492504343953926634992332820282019728792003956564819968;\n\n function abs(int256 a) internal pure returns (uint256) {\n // Required or it will fail when `a = type(int256).min`\n if (a == INT256_MIN) {\n return 57896044618658097711785492504343953926634992332820282019728792003956564819968;\n }\n\n return uint256(a > 0 ? a : -a);\n }\n\n function delta(uint256 a, uint256 b) internal pure returns (uint256) {\n return a > b ? a - b : b - a;\n }\n\n function delta(int256 a, int256 b) internal pure returns (uint256) {\n // a and b are of the same sign\n // this works thanks to two's complement, the left-most bit is the sign bit\n if ((a ^ b) > -1) {\n return delta(abs(a), abs(b));\n }\n\n // a and b are of opposite signs\n return abs(a) + abs(b);\n }\n\n function percentDelta(uint256 a, uint256 b) internal pure returns (uint256) {\n uint256 absDelta = delta(a, b);\n\n return absDelta * 1e18 / b;\n }\n\n function percentDelta(int256 a, int256 b) internal pure returns (uint256) {\n uint256 absDelta = delta(a, b);\n uint256 absB = abs(b);\n\n return absDelta * 1e18 / absB;\n }\n}\n" + }, + "lib/forge-std/src/StdStorage.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.6.2 <0.9.0;\n\nimport {Vm} from \"./Vm.sol\";\n\nstruct FindData {\n uint256 slot;\n uint256 offsetLeft;\n uint256 offsetRight;\n bool found;\n}\n\nstruct StdStorage {\n mapping(address => mapping(bytes4 => mapping(bytes32 => FindData))) finds;\n bytes32[] _keys;\n bytes4 _sig;\n uint256 _depth;\n address _target;\n bytes32 _set;\n bool _enable_packed_slots;\n bytes _calldata;\n}\n\nlibrary stdStorageSafe {\n event SlotFound(address who, bytes4 fsig, bytes32 keysHash, uint256 slot);\n event WARNING_UninitedSlot(address who, uint256 slot);\n\n Vm private constant vm = Vm(address(uint160(uint256(keccak256(\"hevm cheat code\")))));\n uint256 constant UINT256_MAX = 115792089237316195423570985008687907853269984665640564039457584007913129639935;\n\n function sigs(string memory sigStr) internal pure returns (bytes4) {\n return bytes4(keccak256(bytes(sigStr)));\n }\n\n function getCallParams(StdStorage storage self) internal view returns (bytes memory) {\n if (self._calldata.length == 0) {\n return flatten(self._keys);\n } else {\n return self._calldata;\n }\n }\n\n // Calls target contract with configured parameters\n function callTarget(StdStorage storage self) internal view returns (bool, bytes32) {\n bytes memory cald = abi.encodePacked(self._sig, getCallParams(self));\n (bool success, bytes memory rdat) = self._target.staticcall(cald);\n bytes32 result = bytesToBytes32(rdat, 32 * self._depth);\n\n return (success, result);\n }\n\n // Tries mutating slot value to determine if the targeted value is stored in it.\n // If current value is 0, then we are setting slot value to type(uint256).max\n // Otherwise, we set it to 0. That way, return value should always be affected.\n function checkSlotMutatesCall(StdStorage storage self, bytes32 slot) internal returns (bool) {\n bytes32 prevSlotValue = vm.load(self._target, slot);\n (bool success, bytes32 prevReturnValue) = callTarget(self);\n\n bytes32 testVal = prevReturnValue == bytes32(0) ? bytes32(UINT256_MAX) : bytes32(0);\n vm.store(self._target, slot, testVal);\n\n (, bytes32 newReturnValue) = callTarget(self);\n\n vm.store(self._target, slot, prevSlotValue);\n\n return (success && (prevReturnValue != newReturnValue));\n }\n\n // Tries setting one of the bits in slot to 1 until return value changes.\n // Index of resulted bit is an offset packed slot has from left/right side\n function findOffset(StdStorage storage self, bytes32 slot, bool left) internal returns (bool, uint256) {\n for (uint256 offset = 0; offset < 256; offset++) {\n uint256 valueToPut = left ? (1 << (255 - offset)) : (1 << offset);\n vm.store(self._target, slot, bytes32(valueToPut));\n\n (bool success, bytes32 data) = callTarget(self);\n\n if (success && (uint256(data) > 0)) {\n return (true, offset);\n }\n }\n return (false, 0);\n }\n\n function findOffsets(StdStorage storage self, bytes32 slot) internal returns (bool, uint256, uint256) {\n bytes32 prevSlotValue = vm.load(self._target, slot);\n\n (bool foundLeft, uint256 offsetLeft) = findOffset(self, slot, true);\n (bool foundRight, uint256 offsetRight) = findOffset(self, slot, false);\n\n // `findOffset` may mutate slot value, so we are setting it to initial value\n vm.store(self._target, slot, prevSlotValue);\n return (foundLeft && foundRight, offsetLeft, offsetRight);\n }\n\n function find(StdStorage storage self) internal returns (FindData storage) {\n return find(self, true);\n }\n\n /// @notice find an arbitrary storage slot given a function sig, input data, address of the contract and a value to check against\n // slot complexity:\n // if flat, will be bytes32(uint256(uint));\n // if map, will be keccak256(abi.encode(key, uint(slot)));\n // if deep map, will be keccak256(abi.encode(key1, keccak256(abi.encode(key0, uint(slot)))));\n // if map struct, will be bytes32(uint256(keccak256(abi.encode(key1, keccak256(abi.encode(key0, uint(slot)))))) + structFieldDepth);\n function find(StdStorage storage self, bool _clear) internal returns (FindData storage) {\n address who = self._target;\n bytes4 fsig = self._sig;\n uint256 field_depth = self._depth;\n bytes memory params = getCallParams(self);\n\n // calldata to test against\n if (self.finds[who][fsig][keccak256(abi.encodePacked(params, field_depth))].found) {\n if (_clear) {\n clear(self);\n }\n return self.finds[who][fsig][keccak256(abi.encodePacked(params, field_depth))];\n }\n vm.record();\n (, bytes32 callResult) = callTarget(self);\n (bytes32[] memory reads,) = vm.accesses(address(who));\n\n if (reads.length == 0) {\n revert(\"stdStorage find(StdStorage): No storage use detected for target.\");\n } else {\n for (uint256 i = reads.length; --i >= 0;) {\n bytes32 prev = vm.load(who, reads[i]);\n if (prev == bytes32(0)) {\n emit WARNING_UninitedSlot(who, uint256(reads[i]));\n }\n\n if (!checkSlotMutatesCall(self, reads[i])) {\n continue;\n }\n\n (uint256 offsetLeft, uint256 offsetRight) = (0, 0);\n\n if (self._enable_packed_slots) {\n bool found;\n (found, offsetLeft, offsetRight) = findOffsets(self, reads[i]);\n if (!found) {\n continue;\n }\n }\n\n // Check that value between found offsets is equal to the current call result\n uint256 curVal = (uint256(prev) & getMaskByOffsets(offsetLeft, offsetRight)) >> offsetRight;\n\n if (uint256(callResult) != curVal) {\n continue;\n }\n\n emit SlotFound(who, fsig, keccak256(abi.encodePacked(params, field_depth)), uint256(reads[i]));\n self.finds[who][fsig][keccak256(abi.encodePacked(params, field_depth))] =\n FindData(uint256(reads[i]), offsetLeft, offsetRight, true);\n break;\n }\n }\n\n require(\n self.finds[who][fsig][keccak256(abi.encodePacked(params, field_depth))].found,\n \"stdStorage find(StdStorage): Slot(s) not found.\"\n );\n\n if (_clear) {\n clear(self);\n }\n return self.finds[who][fsig][keccak256(abi.encodePacked(params, field_depth))];\n }\n\n function target(StdStorage storage self, address _target) internal returns (StdStorage storage) {\n self._target = _target;\n return self;\n }\n\n function sig(StdStorage storage self, bytes4 _sig) internal returns (StdStorage storage) {\n self._sig = _sig;\n return self;\n }\n\n function sig(StdStorage storage self, string memory _sig) internal returns (StdStorage storage) {\n self._sig = sigs(_sig);\n return self;\n }\n\n function with_calldata(StdStorage storage self, bytes memory _calldata) internal returns (StdStorage storage) {\n self._calldata = _calldata;\n return self;\n }\n\n function with_key(StdStorage storage self, address who) internal returns (StdStorage storage) {\n self._keys.push(bytes32(uint256(uint160(who))));\n return self;\n }\n\n function with_key(StdStorage storage self, uint256 amt) internal returns (StdStorage storage) {\n self._keys.push(bytes32(amt));\n return self;\n }\n\n function with_key(StdStorage storage self, bytes32 key) internal returns (StdStorage storage) {\n self._keys.push(key);\n return self;\n }\n\n function enable_packed_slots(StdStorage storage self) internal returns (StdStorage storage) {\n self._enable_packed_slots = true;\n return self;\n }\n\n function depth(StdStorage storage self, uint256 _depth) internal returns (StdStorage storage) {\n self._depth = _depth;\n return self;\n }\n\n function read(StdStorage storage self) private returns (bytes memory) {\n FindData storage data = find(self, false);\n uint256 mask = getMaskByOffsets(data.offsetLeft, data.offsetRight);\n uint256 value = (uint256(vm.load(self._target, bytes32(data.slot))) & mask) >> data.offsetRight;\n clear(self);\n return abi.encode(value);\n }\n\n function read_bytes32(StdStorage storage self) internal returns (bytes32) {\n return abi.decode(read(self), (bytes32));\n }\n\n function read_bool(StdStorage storage self) internal returns (bool) {\n int256 v = read_int(self);\n if (v == 0) return false;\n if (v == 1) return true;\n revert(\"stdStorage read_bool(StdStorage): Cannot decode. Make sure you are reading a bool.\");\n }\n\n function read_address(StdStorage storage self) internal returns (address) {\n return abi.decode(read(self), (address));\n }\n\n function read_uint(StdStorage storage self) internal returns (uint256) {\n return abi.decode(read(self), (uint256));\n }\n\n function read_int(StdStorage storage self) internal returns (int256) {\n return abi.decode(read(self), (int256));\n }\n\n function parent(StdStorage storage self) internal returns (uint256, bytes32) {\n address who = self._target;\n uint256 field_depth = self._depth;\n vm.startMappingRecording();\n uint256 child = find(self, true).slot - field_depth;\n (bool found, bytes32 key, bytes32 parent_slot) = vm.getMappingKeyAndParentOf(who, bytes32(child));\n if (!found) {\n revert(\n \"stdStorage read_bool(StdStorage): Cannot find parent. Make sure you give a slot and startMappingRecording() has been called.\"\n );\n }\n return (uint256(parent_slot), key);\n }\n\n function root(StdStorage storage self) internal returns (uint256) {\n address who = self._target;\n uint256 field_depth = self._depth;\n vm.startMappingRecording();\n uint256 child = find(self, true).slot - field_depth;\n bool found;\n bytes32 root_slot;\n bytes32 parent_slot;\n (found,, parent_slot) = vm.getMappingKeyAndParentOf(who, bytes32(child));\n if (!found) {\n revert(\n \"stdStorage read_bool(StdStorage): Cannot find parent. Make sure you give a slot and startMappingRecording() has been called.\"\n );\n }\n while (found) {\n root_slot = parent_slot;\n (found,, parent_slot) = vm.getMappingKeyAndParentOf(who, bytes32(root_slot));\n }\n return uint256(root_slot);\n }\n\n function bytesToBytes32(bytes memory b, uint256 offset) private pure returns (bytes32) {\n bytes32 out;\n\n uint256 max = b.length > 32 ? 32 : b.length;\n for (uint256 i = 0; i < max; i++) {\n out |= bytes32(b[offset + i] & 0xFF) >> (i * 8);\n }\n return out;\n }\n\n function flatten(bytes32[] memory b) private pure returns (bytes memory) {\n bytes memory result = new bytes(b.length * 32);\n for (uint256 i = 0; i < b.length; i++) {\n bytes32 k = b[i];\n /// @solidity memory-safe-assembly\n assembly {\n mstore(add(result, add(32, mul(32, i))), k)\n }\n }\n\n return result;\n }\n\n function clear(StdStorage storage self) internal {\n delete self._target;\n delete self._sig;\n delete self._keys;\n delete self._depth;\n delete self._enable_packed_slots;\n delete self._calldata;\n }\n\n // Returns mask which contains non-zero bits for values between `offsetLeft` and `offsetRight`\n // (slotValue & mask) >> offsetRight will be the value of the given packed variable\n function getMaskByOffsets(uint256 offsetLeft, uint256 offsetRight) internal pure returns (uint256 mask) {\n // mask = ((1 << (256 - (offsetRight + offsetLeft))) - 1) << offsetRight;\n // using assembly because (1 << 256) causes overflow\n assembly {\n mask := shl(offsetRight, sub(shl(sub(256, add(offsetRight, offsetLeft)), 1), 1))\n }\n }\n\n // Returns slot value with updated packed variable.\n function getUpdatedSlotValue(bytes32 curValue, uint256 varValue, uint256 offsetLeft, uint256 offsetRight)\n internal\n pure\n returns (bytes32 newValue)\n {\n return bytes32((uint256(curValue) & ~getMaskByOffsets(offsetLeft, offsetRight)) | (varValue << offsetRight));\n }\n}\n\nlibrary stdStorage {\n Vm private constant vm = Vm(address(uint160(uint256(keccak256(\"hevm cheat code\")))));\n\n function sigs(string memory sigStr) internal pure returns (bytes4) {\n return stdStorageSafe.sigs(sigStr);\n }\n\n function find(StdStorage storage self) internal returns (uint256) {\n return find(self, true);\n }\n\n function find(StdStorage storage self, bool _clear) internal returns (uint256) {\n return stdStorageSafe.find(self, _clear).slot;\n }\n\n function target(StdStorage storage self, address _target) internal returns (StdStorage storage) {\n return stdStorageSafe.target(self, _target);\n }\n\n function sig(StdStorage storage self, bytes4 _sig) internal returns (StdStorage storage) {\n return stdStorageSafe.sig(self, _sig);\n }\n\n function sig(StdStorage storage self, string memory _sig) internal returns (StdStorage storage) {\n return stdStorageSafe.sig(self, _sig);\n }\n\n function with_key(StdStorage storage self, address who) internal returns (StdStorage storage) {\n return stdStorageSafe.with_key(self, who);\n }\n\n function with_key(StdStorage storage self, uint256 amt) internal returns (StdStorage storage) {\n return stdStorageSafe.with_key(self, amt);\n }\n\n function with_key(StdStorage storage self, bytes32 key) internal returns (StdStorage storage) {\n return stdStorageSafe.with_key(self, key);\n }\n\n function with_calldata(StdStorage storage self, bytes memory _calldata) internal returns (StdStorage storage) {\n return stdStorageSafe.with_calldata(self, _calldata);\n }\n\n function enable_packed_slots(StdStorage storage self) internal returns (StdStorage storage) {\n return stdStorageSafe.enable_packed_slots(self);\n }\n\n function depth(StdStorage storage self, uint256 _depth) internal returns (StdStorage storage) {\n return stdStorageSafe.depth(self, _depth);\n }\n\n function clear(StdStorage storage self) internal {\n stdStorageSafe.clear(self);\n }\n\n function checked_write(StdStorage storage self, address who) internal {\n checked_write(self, bytes32(uint256(uint160(who))));\n }\n\n function checked_write(StdStorage storage self, uint256 amt) internal {\n checked_write(self, bytes32(amt));\n }\n\n function checked_write_int(StdStorage storage self, int256 val) internal {\n checked_write(self, bytes32(uint256(val)));\n }\n\n function checked_write(StdStorage storage self, bool write) internal {\n bytes32 t;\n /// @solidity memory-safe-assembly\n assembly {\n t := write\n }\n checked_write(self, t);\n }\n\n function checked_write(StdStorage storage self, bytes32 set) internal {\n address who = self._target;\n bytes4 fsig = self._sig;\n uint256 field_depth = self._depth;\n bytes memory params = stdStorageSafe.getCallParams(self);\n\n if (!self.finds[who][fsig][keccak256(abi.encodePacked(params, field_depth))].found) {\n find(self, false);\n }\n FindData storage data = self.finds[who][fsig][keccak256(abi.encodePacked(params, field_depth))];\n if ((data.offsetLeft + data.offsetRight) > 0) {\n uint256 maxVal = 2 ** (256 - (data.offsetLeft + data.offsetRight));\n require(\n uint256(set) < maxVal,\n string(\n abi.encodePacked(\n \"stdStorage find(StdStorage): Packed slot. We can't fit value greater than \",\n vm.toString(maxVal)\n )\n )\n );\n }\n bytes32 curVal = vm.load(who, bytes32(data.slot));\n bytes32 valToSet = stdStorageSafe.getUpdatedSlotValue(curVal, uint256(set), data.offsetLeft, data.offsetRight);\n\n vm.store(who, bytes32(data.slot), valToSet);\n\n (bool success, bytes32 callResult) = stdStorageSafe.callTarget(self);\n\n if (!success || callResult != set) {\n vm.store(who, bytes32(data.slot), curVal);\n revert(\"stdStorage find(StdStorage): Failed to write value.\");\n }\n clear(self);\n }\n\n function read_bytes32(StdStorage storage self) internal returns (bytes32) {\n return stdStorageSafe.read_bytes32(self);\n }\n\n function read_bool(StdStorage storage self) internal returns (bool) {\n return stdStorageSafe.read_bool(self);\n }\n\n function read_address(StdStorage storage self) internal returns (address) {\n return stdStorageSafe.read_address(self);\n }\n\n function read_uint(StdStorage storage self) internal returns (uint256) {\n return stdStorageSafe.read_uint(self);\n }\n\n function read_int(StdStorage storage self) internal returns (int256) {\n return stdStorageSafe.read_int(self);\n }\n\n function parent(StdStorage storage self) internal returns (uint256, bytes32) {\n return stdStorageSafe.parent(self);\n }\n\n function root(StdStorage storage self) internal returns (uint256) {\n return stdStorageSafe.root(self);\n }\n}\n" + }, + "lib/forge-std/src/StdStyle.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.4.22 <0.9.0;\n\nimport {VmSafe} from \"./Vm.sol\";\n\nlibrary StdStyle {\n VmSafe private constant vm = VmSafe(address(uint160(uint256(keccak256(\"hevm cheat code\")))));\n\n string constant RED = \"\\u001b[91m\";\n string constant GREEN = \"\\u001b[92m\";\n string constant YELLOW = \"\\u001b[93m\";\n string constant BLUE = \"\\u001b[94m\";\n string constant MAGENTA = \"\\u001b[95m\";\n string constant CYAN = \"\\u001b[96m\";\n string constant BOLD = \"\\u001b[1m\";\n string constant DIM = \"\\u001b[2m\";\n string constant ITALIC = \"\\u001b[3m\";\n string constant UNDERLINE = \"\\u001b[4m\";\n string constant INVERSE = \"\\u001b[7m\";\n string constant RESET = \"\\u001b[0m\";\n\n function styleConcat(string memory style, string memory self) private pure returns (string memory) {\n return string(abi.encodePacked(style, self, RESET));\n }\n\n function red(string memory self) internal pure returns (string memory) {\n return styleConcat(RED, self);\n }\n\n function red(uint256 self) internal pure returns (string memory) {\n return red(vm.toString(self));\n }\n\n function red(int256 self) internal pure returns (string memory) {\n return red(vm.toString(self));\n }\n\n function red(address self) internal pure returns (string memory) {\n return red(vm.toString(self));\n }\n\n function red(bool self) internal pure returns (string memory) {\n return red(vm.toString(self));\n }\n\n function redBytes(bytes memory self) internal pure returns (string memory) {\n return red(vm.toString(self));\n }\n\n function redBytes32(bytes32 self) internal pure returns (string memory) {\n return red(vm.toString(self));\n }\n\n function green(string memory self) internal pure returns (string memory) {\n return styleConcat(GREEN, self);\n }\n\n function green(uint256 self) internal pure returns (string memory) {\n return green(vm.toString(self));\n }\n\n function green(int256 self) internal pure returns (string memory) {\n return green(vm.toString(self));\n }\n\n function green(address self) internal pure returns (string memory) {\n return green(vm.toString(self));\n }\n\n function green(bool self) internal pure returns (string memory) {\n return green(vm.toString(self));\n }\n\n function greenBytes(bytes memory self) internal pure returns (string memory) {\n return green(vm.toString(self));\n }\n\n function greenBytes32(bytes32 self) internal pure returns (string memory) {\n return green(vm.toString(self));\n }\n\n function yellow(string memory self) internal pure returns (string memory) {\n return styleConcat(YELLOW, self);\n }\n\n function yellow(uint256 self) internal pure returns (string memory) {\n return yellow(vm.toString(self));\n }\n\n function yellow(int256 self) internal pure returns (string memory) {\n return yellow(vm.toString(self));\n }\n\n function yellow(address self) internal pure returns (string memory) {\n return yellow(vm.toString(self));\n }\n\n function yellow(bool self) internal pure returns (string memory) {\n return yellow(vm.toString(self));\n }\n\n function yellowBytes(bytes memory self) internal pure returns (string memory) {\n return yellow(vm.toString(self));\n }\n\n function yellowBytes32(bytes32 self) internal pure returns (string memory) {\n return yellow(vm.toString(self));\n }\n\n function blue(string memory self) internal pure returns (string memory) {\n return styleConcat(BLUE, self);\n }\n\n function blue(uint256 self) internal pure returns (string memory) {\n return blue(vm.toString(self));\n }\n\n function blue(int256 self) internal pure returns (string memory) {\n return blue(vm.toString(self));\n }\n\n function blue(address self) internal pure returns (string memory) {\n return blue(vm.toString(self));\n }\n\n function blue(bool self) internal pure returns (string memory) {\n return blue(vm.toString(self));\n }\n\n function blueBytes(bytes memory self) internal pure returns (string memory) {\n return blue(vm.toString(self));\n }\n\n function blueBytes32(bytes32 self) internal pure returns (string memory) {\n return blue(vm.toString(self));\n }\n\n function magenta(string memory self) internal pure returns (string memory) {\n return styleConcat(MAGENTA, self);\n }\n\n function magenta(uint256 self) internal pure returns (string memory) {\n return magenta(vm.toString(self));\n }\n\n function magenta(int256 self) internal pure returns (string memory) {\n return magenta(vm.toString(self));\n }\n\n function magenta(address self) internal pure returns (string memory) {\n return magenta(vm.toString(self));\n }\n\n function magenta(bool self) internal pure returns (string memory) {\n return magenta(vm.toString(self));\n }\n\n function magentaBytes(bytes memory self) internal pure returns (string memory) {\n return magenta(vm.toString(self));\n }\n\n function magentaBytes32(bytes32 self) internal pure returns (string memory) {\n return magenta(vm.toString(self));\n }\n\n function cyan(string memory self) internal pure returns (string memory) {\n return styleConcat(CYAN, self);\n }\n\n function cyan(uint256 self) internal pure returns (string memory) {\n return cyan(vm.toString(self));\n }\n\n function cyan(int256 self) internal pure returns (string memory) {\n return cyan(vm.toString(self));\n }\n\n function cyan(address self) internal pure returns (string memory) {\n return cyan(vm.toString(self));\n }\n\n function cyan(bool self) internal pure returns (string memory) {\n return cyan(vm.toString(self));\n }\n\n function cyanBytes(bytes memory self) internal pure returns (string memory) {\n return cyan(vm.toString(self));\n }\n\n function cyanBytes32(bytes32 self) internal pure returns (string memory) {\n return cyan(vm.toString(self));\n }\n\n function bold(string memory self) internal pure returns (string memory) {\n return styleConcat(BOLD, self);\n }\n\n function bold(uint256 self) internal pure returns (string memory) {\n return bold(vm.toString(self));\n }\n\n function bold(int256 self) internal pure returns (string memory) {\n return bold(vm.toString(self));\n }\n\n function bold(address self) internal pure returns (string memory) {\n return bold(vm.toString(self));\n }\n\n function bold(bool self) internal pure returns (string memory) {\n return bold(vm.toString(self));\n }\n\n function boldBytes(bytes memory self) internal pure returns (string memory) {\n return bold(vm.toString(self));\n }\n\n function boldBytes32(bytes32 self) internal pure returns (string memory) {\n return bold(vm.toString(self));\n }\n\n function dim(string memory self) internal pure returns (string memory) {\n return styleConcat(DIM, self);\n }\n\n function dim(uint256 self) internal pure returns (string memory) {\n return dim(vm.toString(self));\n }\n\n function dim(int256 self) internal pure returns (string memory) {\n return dim(vm.toString(self));\n }\n\n function dim(address self) internal pure returns (string memory) {\n return dim(vm.toString(self));\n }\n\n function dim(bool self) internal pure returns (string memory) {\n return dim(vm.toString(self));\n }\n\n function dimBytes(bytes memory self) internal pure returns (string memory) {\n return dim(vm.toString(self));\n }\n\n function dimBytes32(bytes32 self) internal pure returns (string memory) {\n return dim(vm.toString(self));\n }\n\n function italic(string memory self) internal pure returns (string memory) {\n return styleConcat(ITALIC, self);\n }\n\n function italic(uint256 self) internal pure returns (string memory) {\n return italic(vm.toString(self));\n }\n\n function italic(int256 self) internal pure returns (string memory) {\n return italic(vm.toString(self));\n }\n\n function italic(address self) internal pure returns (string memory) {\n return italic(vm.toString(self));\n }\n\n function italic(bool self) internal pure returns (string memory) {\n return italic(vm.toString(self));\n }\n\n function italicBytes(bytes memory self) internal pure returns (string memory) {\n return italic(vm.toString(self));\n }\n\n function italicBytes32(bytes32 self) internal pure returns (string memory) {\n return italic(vm.toString(self));\n }\n\n function underline(string memory self) internal pure returns (string memory) {\n return styleConcat(UNDERLINE, self);\n }\n\n function underline(uint256 self) internal pure returns (string memory) {\n return underline(vm.toString(self));\n }\n\n function underline(int256 self) internal pure returns (string memory) {\n return underline(vm.toString(self));\n }\n\n function underline(address self) internal pure returns (string memory) {\n return underline(vm.toString(self));\n }\n\n function underline(bool self) internal pure returns (string memory) {\n return underline(vm.toString(self));\n }\n\n function underlineBytes(bytes memory self) internal pure returns (string memory) {\n return underline(vm.toString(self));\n }\n\n function underlineBytes32(bytes32 self) internal pure returns (string memory) {\n return underline(vm.toString(self));\n }\n\n function inverse(string memory self) internal pure returns (string memory) {\n return styleConcat(INVERSE, self);\n }\n\n function inverse(uint256 self) internal pure returns (string memory) {\n return inverse(vm.toString(self));\n }\n\n function inverse(int256 self) internal pure returns (string memory) {\n return inverse(vm.toString(self));\n }\n\n function inverse(address self) internal pure returns (string memory) {\n return inverse(vm.toString(self));\n }\n\n function inverse(bool self) internal pure returns (string memory) {\n return inverse(vm.toString(self));\n }\n\n function inverseBytes(bytes memory self) internal pure returns (string memory) {\n return inverse(vm.toString(self));\n }\n\n function inverseBytes32(bytes32 self) internal pure returns (string memory) {\n return inverse(vm.toString(self));\n }\n}\n" + }, + "lib/forge-std/src/StdToml.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.6.0 <0.9.0;\n\npragma experimental ABIEncoderV2;\n\nimport {VmSafe} from \"./Vm.sol\";\n\n// Helpers for parsing and writing TOML files\n// To parse:\n// ```\n// using stdToml for string;\n// string memory toml = vm.readFile(\"\");\n// toml.readUint(\"\");\n// ```\n// To write:\n// ```\n// using stdToml for string;\n// string memory json = \"json\";\n// json.serialize(\"a\", uint256(123));\n// string memory semiFinal = json.serialize(\"b\", string(\"test\"));\n// string memory finalJson = json.serialize(\"c\", semiFinal);\n// finalJson.write(\"\");\n// ```\n\nlibrary stdToml {\n VmSafe private constant vm = VmSafe(address(uint160(uint256(keccak256(\"hevm cheat code\")))));\n\n function keyExists(string memory toml, string memory key) internal view returns (bool) {\n return vm.keyExistsToml(toml, key);\n }\n\n function parseRaw(string memory toml, string memory key) internal pure returns (bytes memory) {\n return vm.parseToml(toml, key);\n }\n\n function readUint(string memory toml, string memory key) internal pure returns (uint256) {\n return vm.parseTomlUint(toml, key);\n }\n\n function readUintArray(string memory toml, string memory key) internal pure returns (uint256[] memory) {\n return vm.parseTomlUintArray(toml, key);\n }\n\n function readInt(string memory toml, string memory key) internal pure returns (int256) {\n return vm.parseTomlInt(toml, key);\n }\n\n function readIntArray(string memory toml, string memory key) internal pure returns (int256[] memory) {\n return vm.parseTomlIntArray(toml, key);\n }\n\n function readBytes32(string memory toml, string memory key) internal pure returns (bytes32) {\n return vm.parseTomlBytes32(toml, key);\n }\n\n function readBytes32Array(string memory toml, string memory key) internal pure returns (bytes32[] memory) {\n return vm.parseTomlBytes32Array(toml, key);\n }\n\n function readString(string memory toml, string memory key) internal pure returns (string memory) {\n return vm.parseTomlString(toml, key);\n }\n\n function readStringArray(string memory toml, string memory key) internal pure returns (string[] memory) {\n return vm.parseTomlStringArray(toml, key);\n }\n\n function readAddress(string memory toml, string memory key) internal pure returns (address) {\n return vm.parseTomlAddress(toml, key);\n }\n\n function readAddressArray(string memory toml, string memory key) internal pure returns (address[] memory) {\n return vm.parseTomlAddressArray(toml, key);\n }\n\n function readBool(string memory toml, string memory key) internal pure returns (bool) {\n return vm.parseTomlBool(toml, key);\n }\n\n function readBoolArray(string memory toml, string memory key) internal pure returns (bool[] memory) {\n return vm.parseTomlBoolArray(toml, key);\n }\n\n function readBytes(string memory toml, string memory key) internal pure returns (bytes memory) {\n return vm.parseTomlBytes(toml, key);\n }\n\n function readBytesArray(string memory toml, string memory key) internal pure returns (bytes[] memory) {\n return vm.parseTomlBytesArray(toml, key);\n }\n\n function readUintOr(string memory toml, string memory key, uint256 defaultValue) internal view returns (uint256) {\n return keyExists(toml, key) ? readUint(toml, key) : defaultValue;\n }\n\n function readUintArrayOr(string memory toml, string memory key, uint256[] memory defaultValue)\n internal\n view\n returns (uint256[] memory)\n {\n return keyExists(toml, key) ? readUintArray(toml, key) : defaultValue;\n }\n\n function readIntOr(string memory toml, string memory key, int256 defaultValue) internal view returns (int256) {\n return keyExists(toml, key) ? readInt(toml, key) : defaultValue;\n }\n\n function readIntArrayOr(string memory toml, string memory key, int256[] memory defaultValue)\n internal\n view\n returns (int256[] memory)\n {\n return keyExists(toml, key) ? readIntArray(toml, key) : defaultValue;\n }\n\n function readBytes32Or(string memory toml, string memory key, bytes32 defaultValue)\n internal\n view\n returns (bytes32)\n {\n return keyExists(toml, key) ? readBytes32(toml, key) : defaultValue;\n }\n\n function readBytes32ArrayOr(string memory toml, string memory key, bytes32[] memory defaultValue)\n internal\n view\n returns (bytes32[] memory)\n {\n return keyExists(toml, key) ? readBytes32Array(toml, key) : defaultValue;\n }\n\n function readStringOr(string memory toml, string memory key, string memory defaultValue)\n internal\n view\n returns (string memory)\n {\n return keyExists(toml, key) ? readString(toml, key) : defaultValue;\n }\n\n function readStringArrayOr(string memory toml, string memory key, string[] memory defaultValue)\n internal\n view\n returns (string[] memory)\n {\n return keyExists(toml, key) ? readStringArray(toml, key) : defaultValue;\n }\n\n function readAddressOr(string memory toml, string memory key, address defaultValue)\n internal\n view\n returns (address)\n {\n return keyExists(toml, key) ? readAddress(toml, key) : defaultValue;\n }\n\n function readAddressArrayOr(string memory toml, string memory key, address[] memory defaultValue)\n internal\n view\n returns (address[] memory)\n {\n return keyExists(toml, key) ? readAddressArray(toml, key) : defaultValue;\n }\n\n function readBoolOr(string memory toml, string memory key, bool defaultValue) internal view returns (bool) {\n return keyExists(toml, key) ? readBool(toml, key) : defaultValue;\n }\n\n function readBoolArrayOr(string memory toml, string memory key, bool[] memory defaultValue)\n internal\n view\n returns (bool[] memory)\n {\n return keyExists(toml, key) ? readBoolArray(toml, key) : defaultValue;\n }\n\n function readBytesOr(string memory toml, string memory key, bytes memory defaultValue)\n internal\n view\n returns (bytes memory)\n {\n return keyExists(toml, key) ? readBytes(toml, key) : defaultValue;\n }\n\n function readBytesArrayOr(string memory toml, string memory key, bytes[] memory defaultValue)\n internal\n view\n returns (bytes[] memory)\n {\n return keyExists(toml, key) ? readBytesArray(toml, key) : defaultValue;\n }\n\n function serialize(string memory jsonKey, string memory rootObject) internal returns (string memory) {\n return vm.serializeJson(jsonKey, rootObject);\n }\n\n function serialize(string memory jsonKey, string memory key, bool value) internal returns (string memory) {\n return vm.serializeBool(jsonKey, key, value);\n }\n\n function serialize(string memory jsonKey, string memory key, bool[] memory value)\n internal\n returns (string memory)\n {\n return vm.serializeBool(jsonKey, key, value);\n }\n\n function serialize(string memory jsonKey, string memory key, uint256 value) internal returns (string memory) {\n return vm.serializeUint(jsonKey, key, value);\n }\n\n function serialize(string memory jsonKey, string memory key, uint256[] memory value)\n internal\n returns (string memory)\n {\n return vm.serializeUint(jsonKey, key, value);\n }\n\n function serialize(string memory jsonKey, string memory key, int256 value) internal returns (string memory) {\n return vm.serializeInt(jsonKey, key, value);\n }\n\n function serialize(string memory jsonKey, string memory key, int256[] memory value)\n internal\n returns (string memory)\n {\n return vm.serializeInt(jsonKey, key, value);\n }\n\n function serialize(string memory jsonKey, string memory key, address value) internal returns (string memory) {\n return vm.serializeAddress(jsonKey, key, value);\n }\n\n function serialize(string memory jsonKey, string memory key, address[] memory value)\n internal\n returns (string memory)\n {\n return vm.serializeAddress(jsonKey, key, value);\n }\n\n function serialize(string memory jsonKey, string memory key, bytes32 value) internal returns (string memory) {\n return vm.serializeBytes32(jsonKey, key, value);\n }\n\n function serialize(string memory jsonKey, string memory key, bytes32[] memory value)\n internal\n returns (string memory)\n {\n return vm.serializeBytes32(jsonKey, key, value);\n }\n\n function serialize(string memory jsonKey, string memory key, bytes memory value) internal returns (string memory) {\n return vm.serializeBytes(jsonKey, key, value);\n }\n\n function serialize(string memory jsonKey, string memory key, bytes[] memory value)\n internal\n returns (string memory)\n {\n return vm.serializeBytes(jsonKey, key, value);\n }\n\n function serialize(string memory jsonKey, string memory key, string memory value)\n internal\n returns (string memory)\n {\n return vm.serializeString(jsonKey, key, value);\n }\n\n function serialize(string memory jsonKey, string memory key, string[] memory value)\n internal\n returns (string memory)\n {\n return vm.serializeString(jsonKey, key, value);\n }\n\n function write(string memory jsonKey, string memory path) internal {\n vm.writeToml(jsonKey, path);\n }\n\n function write(string memory jsonKey, string memory path, string memory valueKey) internal {\n vm.writeToml(jsonKey, path, valueKey);\n }\n}\n" + }, + "lib/forge-std/src/StdUtils.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.6.2 <0.9.0;\n\npragma experimental ABIEncoderV2;\n\nimport {IMulticall3} from \"./interfaces/IMulticall3.sol\";\nimport {MockERC20} from \"./mocks/MockERC20.sol\";\nimport {MockERC721} from \"./mocks/MockERC721.sol\";\nimport {VmSafe} from \"./Vm.sol\";\n\nabstract contract StdUtils {\n /*//////////////////////////////////////////////////////////////////////////\n CONSTANTS\n //////////////////////////////////////////////////////////////////////////*/\n\n IMulticall3 private constant multicall = IMulticall3(0xcA11bde05977b3631167028862bE2a173976CA11);\n VmSafe private constant vm = VmSafe(address(uint160(uint256(keccak256(\"hevm cheat code\")))));\n address private constant CONSOLE2_ADDRESS = 0x000000000000000000636F6e736F6c652e6c6f67;\n uint256 private constant INT256_MIN_ABS =\n 57896044618658097711785492504343953926634992332820282019728792003956564819968;\n uint256 private constant SECP256K1_ORDER =\n 115792089237316195423570985008687907852837564279074904382605163141518161494337;\n uint256 private constant UINT256_MAX =\n 115792089237316195423570985008687907853269984665640564039457584007913129639935;\n\n // Used by default when deploying with create2, https://github.com/Arachnid/deterministic-deployment-proxy.\n address private constant CREATE2_FACTORY = 0x4e59b44847b379578588920cA78FbF26c0B4956C;\n\n /*//////////////////////////////////////////////////////////////////////////\n INTERNAL FUNCTIONS\n //////////////////////////////////////////////////////////////////////////*/\n\n function _bound(uint256 x, uint256 min, uint256 max) internal pure virtual returns (uint256 result) {\n require(min <= max, \"StdUtils bound(uint256,uint256,uint256): Max is less than min.\");\n // If x is between min and max, return x directly. This is to ensure that dictionary values\n // do not get shifted if the min is nonzero. More info: https://github.com/foundry-rs/forge-std/issues/188\n if (x >= min && x <= max) return x;\n\n uint256 size = max - min + 1;\n\n // If the value is 0, 1, 2, 3, wrap that to min, min+1, min+2, min+3. Similarly for the UINT256_MAX side.\n // This helps ensure coverage of the min/max values.\n if (x <= 3 && size > x) return min + x;\n if (x >= UINT256_MAX - 3 && size > UINT256_MAX - x) return max - (UINT256_MAX - x);\n\n // Otherwise, wrap x into the range [min, max], i.e. the range is inclusive.\n if (x > max) {\n uint256 diff = x - max;\n uint256 rem = diff % size;\n if (rem == 0) return max;\n result = min + rem - 1;\n } else if (x < min) {\n uint256 diff = min - x;\n uint256 rem = diff % size;\n if (rem == 0) return min;\n result = max - rem + 1;\n }\n }\n\n function bound(uint256 x, uint256 min, uint256 max) internal pure virtual returns (uint256 result) {\n result = _bound(x, min, max);\n console2_log_StdUtils(\"Bound result\", result);\n }\n\n function _bound(int256 x, int256 min, int256 max) internal pure virtual returns (int256 result) {\n require(min <= max, \"StdUtils bound(int256,int256,int256): Max is less than min.\");\n\n // Shifting all int256 values to uint256 to use _bound function. The range of two types are:\n // int256 : -(2**255) ~ (2**255 - 1)\n // uint256: 0 ~ (2**256 - 1)\n // So, add 2**255, INT256_MIN_ABS to the integer values.\n //\n // If the given integer value is -2**255, we cannot use `-uint256(-x)` because of the overflow.\n // So, use `~uint256(x) + 1` instead.\n uint256 _x = x < 0 ? (INT256_MIN_ABS - ~uint256(x) - 1) : (uint256(x) + INT256_MIN_ABS);\n uint256 _min = min < 0 ? (INT256_MIN_ABS - ~uint256(min) - 1) : (uint256(min) + INT256_MIN_ABS);\n uint256 _max = max < 0 ? (INT256_MIN_ABS - ~uint256(max) - 1) : (uint256(max) + INT256_MIN_ABS);\n\n uint256 y = _bound(_x, _min, _max);\n\n // To move it back to int256 value, subtract INT256_MIN_ABS at here.\n result = y < INT256_MIN_ABS ? int256(~(INT256_MIN_ABS - y) + 1) : int256(y - INT256_MIN_ABS);\n }\n\n function bound(int256 x, int256 min, int256 max) internal pure virtual returns (int256 result) {\n result = _bound(x, min, max);\n console2_log_StdUtils(\"Bound result\", vm.toString(result));\n }\n\n function boundPrivateKey(uint256 privateKey) internal pure virtual returns (uint256 result) {\n result = _bound(privateKey, 1, SECP256K1_ORDER - 1);\n }\n\n function bytesToUint(bytes memory b) internal pure virtual returns (uint256) {\n require(b.length <= 32, \"StdUtils bytesToUint(bytes): Bytes length exceeds 32.\");\n return abi.decode(abi.encodePacked(new bytes(32 - b.length), b), (uint256));\n }\n\n /// @dev Compute the address a contract will be deployed at for a given deployer address and nonce\n /// @notice adapted from Solmate implementation (https://github.com/Rari-Capital/solmate/blob/main/src/utils/LibRLP.sol)\n function computeCreateAddress(address deployer, uint256 nonce) internal pure virtual returns (address) {\n console2_log_StdUtils(\"computeCreateAddress is deprecated. Please use vm.computeCreateAddress instead.\");\n return vm.computeCreateAddress(deployer, nonce);\n }\n\n function computeCreate2Address(bytes32 salt, bytes32 initcodeHash, address deployer)\n internal\n pure\n virtual\n returns (address)\n {\n console2_log_StdUtils(\"computeCreate2Address is deprecated. Please use vm.computeCreate2Address instead.\");\n return vm.computeCreate2Address(salt, initcodeHash, deployer);\n }\n\n /// @dev returns the address of a contract created with CREATE2 using the default CREATE2 deployer\n function computeCreate2Address(bytes32 salt, bytes32 initCodeHash) internal pure returns (address) {\n console2_log_StdUtils(\"computeCreate2Address is deprecated. Please use vm.computeCreate2Address instead.\");\n return vm.computeCreate2Address(salt, initCodeHash);\n }\n\n /// @dev returns an initialized mock ERC20 contract\n function deployMockERC20(string memory name, string memory symbol, uint8 decimals)\n internal\n returns (MockERC20 mock)\n {\n mock = new MockERC20();\n mock.initialize(name, symbol, decimals);\n }\n\n /// @dev returns an initialized mock ERC721 contract\n function deployMockERC721(string memory name, string memory symbol) internal returns (MockERC721 mock) {\n mock = new MockERC721();\n mock.initialize(name, symbol);\n }\n\n /// @dev returns the hash of the init code (creation code + no args) used in CREATE2 with no constructor arguments\n /// @param creationCode the creation code of a contract C, as returned by type(C).creationCode\n function hashInitCode(bytes memory creationCode) internal pure returns (bytes32) {\n return hashInitCode(creationCode, \"\");\n }\n\n /// @dev returns the hash of the init code (creation code + ABI-encoded args) used in CREATE2\n /// @param creationCode the creation code of a contract C, as returned by type(C).creationCode\n /// @param args the ABI-encoded arguments to the constructor of C\n function hashInitCode(bytes memory creationCode, bytes memory args) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(creationCode, args));\n }\n\n // Performs a single call with Multicall3 to query the ERC-20 token balances of the given addresses.\n function getTokenBalances(address token, address[] memory addresses)\n internal\n virtual\n returns (uint256[] memory balances)\n {\n uint256 tokenCodeSize;\n assembly {\n tokenCodeSize := extcodesize(token)\n }\n require(tokenCodeSize > 0, \"StdUtils getTokenBalances(address,address[]): Token address is not a contract.\");\n\n // ABI encode the aggregate call to Multicall3.\n uint256 length = addresses.length;\n IMulticall3.Call[] memory calls = new IMulticall3.Call[](length);\n for (uint256 i = 0; i < length; ++i) {\n // 0x70a08231 = bytes4(\"balanceOf(address)\"))\n calls[i] = IMulticall3.Call({target: token, callData: abi.encodeWithSelector(0x70a08231, (addresses[i]))});\n }\n\n // Make the aggregate call.\n (, bytes[] memory returnData) = multicall.aggregate(calls);\n\n // ABI decode the return data and return the balances.\n balances = new uint256[](length);\n for (uint256 i = 0; i < length; ++i) {\n balances[i] = abi.decode(returnData[i], (uint256));\n }\n }\n\n /*//////////////////////////////////////////////////////////////////////////\n PRIVATE FUNCTIONS\n //////////////////////////////////////////////////////////////////////////*/\n\n function addressFromLast20Bytes(bytes32 bytesValue) private pure returns (address) {\n return address(uint160(uint256(bytesValue)));\n }\n\n // This section is used to prevent the compilation of console, which shortens the compilation time when console is\n // not used elsewhere. We also trick the compiler into letting us make the console log methods as `pure` to avoid\n // any breaking changes to function signatures.\n function _castLogPayloadViewToPure(function(bytes memory) internal view fnIn)\n internal\n pure\n returns (function(bytes memory) internal pure fnOut)\n {\n assembly {\n fnOut := fnIn\n }\n }\n\n function _sendLogPayload(bytes memory payload) internal pure {\n _castLogPayloadViewToPure(_sendLogPayloadView)(payload);\n }\n\n function _sendLogPayloadView(bytes memory payload) private view {\n uint256 payloadLength = payload.length;\n address consoleAddress = CONSOLE2_ADDRESS;\n /// @solidity memory-safe-assembly\n assembly {\n let payloadStart := add(payload, 32)\n let r := staticcall(gas(), consoleAddress, payloadStart, payloadLength, 0, 0)\n }\n }\n\n function console2_log_StdUtils(string memory p0) private pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string)\", p0));\n }\n\n function console2_log_StdUtils(string memory p0, uint256 p1) private pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256)\", p0, p1));\n }\n\n function console2_log_StdUtils(string memory p0, string memory p1) private pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string)\", p0, p1));\n }\n}\n" + }, + "lib/forge-std/src/Test.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.6.2 <0.9.0;\n\npragma experimental ABIEncoderV2;\n\n// 💬 ABOUT\n// Forge Std's default Test.\n\n// 🧩 MODULES\nimport {console} from \"./console.sol\";\nimport {console2} from \"./console2.sol\";\nimport {safeconsole} from \"./safeconsole.sol\";\nimport {StdAssertions} from \"./StdAssertions.sol\";\nimport {StdChains} from \"./StdChains.sol\";\nimport {StdCheats} from \"./StdCheats.sol\";\nimport {stdError} from \"./StdError.sol\";\nimport {StdInvariant} from \"./StdInvariant.sol\";\nimport {stdJson} from \"./StdJson.sol\";\nimport {stdMath} from \"./StdMath.sol\";\nimport {StdStorage, stdStorage} from \"./StdStorage.sol\";\nimport {StdStyle} from \"./StdStyle.sol\";\nimport {stdToml} from \"./StdToml.sol\";\nimport {StdUtils} from \"./StdUtils.sol\";\nimport {Vm} from \"./Vm.sol\";\n\n// 📦 BOILERPLATE\nimport {TestBase} from \"./Base.sol\";\n\n// ⭐️ TEST\nabstract contract Test is TestBase, StdAssertions, StdChains, StdCheats, StdInvariant, StdUtils {\n // Note: IS_TEST() must return true.\n bool public IS_TEST = true;\n}\n" + }, + "lib/forge-std/src/Vm.sol": { + "content": "// Automatically @generated by scripts/vm.py. Do not modify manually.\n\n// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity >=0.6.2 <0.9.0;\npragma experimental ABIEncoderV2;\n\n/// The `VmSafe` interface does not allow manipulation of the EVM state or other actions that may\n/// result in Script simulations differing from on-chain execution. It is recommended to only use\n/// these cheats in scripts.\ninterface VmSafe {\n /// A modification applied to either `msg.sender` or `tx.origin`. Returned by `readCallers`.\n enum CallerMode {\n // No caller modification is currently active.\n None,\n // A one time broadcast triggered by a `vm.broadcast()` call is currently active.\n Broadcast,\n // A recurrent broadcast triggered by a `vm.startBroadcast()` call is currently active.\n RecurrentBroadcast,\n // A one time prank triggered by a `vm.prank()` call is currently active.\n Prank,\n // A recurrent prank triggered by a `vm.startPrank()` call is currently active.\n RecurrentPrank\n }\n\n /// The kind of account access that occurred.\n enum AccountAccessKind {\n // The account was called.\n Call,\n // The account was called via delegatecall.\n DelegateCall,\n // The account was called via callcode.\n CallCode,\n // The account was called via staticcall.\n StaticCall,\n // The account was created.\n Create,\n // The account was selfdestructed.\n SelfDestruct,\n // Synthetic access indicating the current context has resumed after a previous sub-context (AccountAccess).\n Resume,\n // The account's balance was read.\n Balance,\n // The account's codesize was read.\n Extcodesize,\n // The account's codehash was read.\n Extcodehash,\n // The account's code was copied.\n Extcodecopy\n }\n\n /// Forge execution contexts.\n enum ForgeContext {\n // Test group execution context (test, coverage or snapshot).\n TestGroup,\n // `forge test` execution context.\n Test,\n // `forge coverage` execution context.\n Coverage,\n // `forge snapshot` execution context.\n Snapshot,\n // Script group execution context (dry run, broadcast or resume).\n ScriptGroup,\n // `forge script` execution context.\n ScriptDryRun,\n // `forge script --broadcast` execution context.\n ScriptBroadcast,\n // `forge script --resume` execution context.\n ScriptResume,\n // Unknown `forge` execution context.\n Unknown\n }\n\n /// The transaction type (`txType`) of the broadcast.\n enum BroadcastTxType {\n // Represents a CALL broadcast tx.\n Call,\n // Represents a CREATE broadcast tx.\n Create,\n // Represents a CREATE2 broadcast tx.\n Create2\n }\n\n /// An Ethereum log. Returned by `getRecordedLogs`.\n struct Log {\n // The topics of the log, including the signature, if any.\n bytes32[] topics;\n // The raw data of the log.\n bytes data;\n // The address of the log's emitter.\n address emitter;\n }\n\n /// An RPC URL and its alias. Returned by `rpcUrlStructs`.\n struct Rpc {\n // The alias of the RPC URL.\n string key;\n // The RPC URL.\n string url;\n }\n\n /// An RPC log object. Returned by `eth_getLogs`.\n struct EthGetLogs {\n // The address of the log's emitter.\n address emitter;\n // The topics of the log, including the signature, if any.\n bytes32[] topics;\n // The raw data of the log.\n bytes data;\n // The block hash.\n bytes32 blockHash;\n // The block number.\n uint64 blockNumber;\n // The transaction hash.\n bytes32 transactionHash;\n // The transaction index in the block.\n uint64 transactionIndex;\n // The log index.\n uint256 logIndex;\n // Whether the log was removed.\n bool removed;\n }\n\n /// A single entry in a directory listing. Returned by `readDir`.\n struct DirEntry {\n // The error message, if any.\n string errorMessage;\n // The path of the entry.\n string path;\n // The depth of the entry.\n uint64 depth;\n // Whether the entry is a directory.\n bool isDir;\n // Whether the entry is a symlink.\n bool isSymlink;\n }\n\n /// Metadata information about a file.\n /// This structure is returned from the `fsMetadata` function and represents known\n /// metadata about a file such as its permissions, size, modification\n /// times, etc.\n struct FsMetadata {\n // True if this metadata is for a directory.\n bool isDir;\n // True if this metadata is for a symlink.\n bool isSymlink;\n // The size of the file, in bytes, this metadata is for.\n uint256 length;\n // True if this metadata is for a readonly (unwritable) file.\n bool readOnly;\n // The last modification time listed in this metadata.\n uint256 modified;\n // The last access time of this metadata.\n uint256 accessed;\n // The creation time listed in this metadata.\n uint256 created;\n }\n\n /// A wallet with a public and private key.\n struct Wallet {\n // The wallet's address.\n address addr;\n // The wallet's public key `X`.\n uint256 publicKeyX;\n // The wallet's public key `Y`.\n uint256 publicKeyY;\n // The wallet's private key.\n uint256 privateKey;\n }\n\n /// The result of a `tryFfi` call.\n struct FfiResult {\n // The exit code of the call.\n int32 exitCode;\n // The optionally hex-decoded `stdout` data.\n bytes stdout;\n // The `stderr` data.\n bytes stderr;\n }\n\n /// Information on the chain and fork.\n struct ChainInfo {\n // The fork identifier. Set to zero if no fork is active.\n uint256 forkId;\n // The chain ID of the current fork.\n uint256 chainId;\n }\n\n /// The result of a `stopAndReturnStateDiff` call.\n struct AccountAccess {\n // The chain and fork the access occurred.\n ChainInfo chainInfo;\n // The kind of account access that determines what the account is.\n // If kind is Call, DelegateCall, StaticCall or CallCode, then the account is the callee.\n // If kind is Create, then the account is the newly created account.\n // If kind is SelfDestruct, then the account is the selfdestruct recipient.\n // If kind is a Resume, then account represents a account context that has resumed.\n AccountAccessKind kind;\n // The account that was accessed.\n // It's either the account created, callee or a selfdestruct recipient for CREATE, CALL or SELFDESTRUCT.\n address account;\n // What accessed the account.\n address accessor;\n // If the account was initialized or empty prior to the access.\n // An account is considered initialized if it has code, a\n // non-zero nonce, or a non-zero balance.\n bool initialized;\n // The previous balance of the accessed account.\n uint256 oldBalance;\n // The potential new balance of the accessed account.\n // That is, all balance changes are recorded here, even if reverts occurred.\n uint256 newBalance;\n // Code of the account deployed by CREATE.\n bytes deployedCode;\n // Value passed along with the account access\n uint256 value;\n // Input data provided to the CREATE or CALL\n bytes data;\n // If this access reverted in either the current or parent context.\n bool reverted;\n // An ordered list of storage accesses made during an account access operation.\n StorageAccess[] storageAccesses;\n // Call depth traversed during the recording of state differences\n uint64 depth;\n }\n\n /// The storage accessed during an `AccountAccess`.\n struct StorageAccess {\n // The account whose storage was accessed.\n address account;\n // The slot that was accessed.\n bytes32 slot;\n // If the access was a write.\n bool isWrite;\n // The previous value of the slot.\n bytes32 previousValue;\n // The new value of the slot.\n bytes32 newValue;\n // If the access was reverted.\n bool reverted;\n }\n\n /// Gas used. Returned by `lastCallGas`.\n struct Gas {\n // The gas limit of the call.\n uint64 gasLimit;\n // The total gas used.\n uint64 gasTotalUsed;\n // DEPRECATED: The amount of gas used for memory expansion. Ref: \n uint64 gasMemoryUsed;\n // The amount of gas refunded.\n int64 gasRefunded;\n // The amount of gas remaining.\n uint64 gasRemaining;\n }\n\n /// The result of the `stopDebugTraceRecording` call\n struct DebugStep {\n // The stack before executing the step of the run.\n // stack\\[0\\] represents the top of the stack.\n // and only stack data relevant to the opcode execution is contained.\n uint256[] stack;\n // The memory input data before executing the step of the run.\n // only input data relevant to the opcode execution is contained.\n // e.g. for MLOAD, it will have memory\\[offset:offset+32\\] copied here.\n // the offset value can be get by the stack data.\n bytes memoryInput;\n // The opcode that was accessed.\n uint8 opcode;\n // The call depth of the step.\n uint64 depth;\n // Whether the call end up with out of gas error.\n bool isOutOfGas;\n // The contract address where the opcode is running\n address contractAddr;\n }\n\n /// Represents a transaction's broadcast details.\n struct BroadcastTxSummary {\n // The hash of the transaction that was broadcasted\n bytes32 txHash;\n // Represent the type of transaction among CALL, CREATE, CREATE2\n BroadcastTxType txType;\n // The address of the contract that was called or created.\n // This is address of the contract that is created if the txType is CREATE or CREATE2.\n address contractAddress;\n // The block number the transaction landed in.\n uint64 blockNumber;\n // Status of the transaction, retrieved from the transaction receipt.\n bool success;\n }\n\n /// Holds a signed EIP-7702 authorization for an authority account to delegate to an implementation.\n struct SignedDelegation {\n // The y-parity of the recovered secp256k1 signature (0 or 1).\n uint8 v;\n // First 32 bytes of the signature.\n bytes32 r;\n // Second 32 bytes of the signature.\n bytes32 s;\n // The current nonce of the authority account at signing time.\n // Used to ensure signature can't be replayed after account nonce changes.\n uint64 nonce;\n // Address of the contract implementation that will be delegated to.\n // Gets encoded into delegation code: 0xef0100 || implementation.\n address implementation;\n }\n\n // ======== Crypto ========\n\n /// Derives a private key from the name, labels the account with that name, and returns the wallet.\n function createWallet(string calldata walletLabel) external returns (Wallet memory wallet);\n\n /// Generates a wallet from the private key and returns the wallet.\n function createWallet(uint256 privateKey) external returns (Wallet memory wallet);\n\n /// Generates a wallet from the private key, labels the account with that name, and returns the wallet.\n function createWallet(uint256 privateKey, string calldata walletLabel) external returns (Wallet memory wallet);\n\n /// Derive a private key from a provided mnenomic string (or mnenomic file path)\n /// at the derivation path `m/44'/60'/0'/0/{index}`.\n function deriveKey(string calldata mnemonic, uint32 index) external pure returns (uint256 privateKey);\n\n /// Derive a private key from a provided mnenomic string (or mnenomic file path)\n /// at `{derivationPath}{index}`.\n function deriveKey(string calldata mnemonic, string calldata derivationPath, uint32 index)\n external\n pure\n returns (uint256 privateKey);\n\n /// Derive a private key from a provided mnenomic string (or mnenomic file path) in the specified language\n /// at the derivation path `m/44'/60'/0'/0/{index}`.\n function deriveKey(string calldata mnemonic, uint32 index, string calldata language)\n external\n pure\n returns (uint256 privateKey);\n\n /// Derive a private key from a provided mnenomic string (or mnenomic file path) in the specified language\n /// at `{derivationPath}{index}`.\n function deriveKey(string calldata mnemonic, string calldata derivationPath, uint32 index, string calldata language)\n external\n pure\n returns (uint256 privateKey);\n\n /// Derives secp256r1 public key from the provided `privateKey`.\n function publicKeyP256(uint256 privateKey) external pure returns (uint256 publicKeyX, uint256 publicKeyY);\n\n /// Adds a private key to the local forge wallet and returns the address.\n function rememberKey(uint256 privateKey) external returns (address keyAddr);\n\n /// Derive a set number of wallets from a mnemonic at the derivation path `m/44'/60'/0'/0/{0..count}`.\n /// The respective private keys are saved to the local forge wallet for later use and their addresses are returned.\n function rememberKeys(string calldata mnemonic, string calldata derivationPath, uint32 count)\n external\n returns (address[] memory keyAddrs);\n\n /// Derive a set number of wallets from a mnemonic in the specified language at the derivation path `m/44'/60'/0'/0/{0..count}`.\n /// The respective private keys are saved to the local forge wallet for later use and their addresses are returned.\n function rememberKeys(\n string calldata mnemonic,\n string calldata derivationPath,\n string calldata language,\n uint32 count\n ) external returns (address[] memory keyAddrs);\n\n /// Signs data with a `Wallet`.\n /// Returns a compact signature (`r`, `vs`) as per EIP-2098, where `vs` encodes both the\n /// signature's `s` value, and the recovery id `v` in a single bytes32.\n /// This format reduces the signature size from 65 to 64 bytes.\n function signCompact(Wallet calldata wallet, bytes32 digest) external returns (bytes32 r, bytes32 vs);\n\n /// Signs `digest` with `privateKey` using the secp256k1 curve.\n /// Returns a compact signature (`r`, `vs`) as per EIP-2098, where `vs` encodes both the\n /// signature's `s` value, and the recovery id `v` in a single bytes32.\n /// This format reduces the signature size from 65 to 64 bytes.\n function signCompact(uint256 privateKey, bytes32 digest) external pure returns (bytes32 r, bytes32 vs);\n\n /// Signs `digest` with signer provided to script using the secp256k1 curve.\n /// Returns a compact signature (`r`, `vs`) as per EIP-2098, where `vs` encodes both the\n /// signature's `s` value, and the recovery id `v` in a single bytes32.\n /// This format reduces the signature size from 65 to 64 bytes.\n /// If `--sender` is provided, the signer with provided address is used, otherwise,\n /// if exactly one signer is provided to the script, that signer is used.\n /// Raises error if signer passed through `--sender` does not match any unlocked signers or\n /// if `--sender` is not provided and not exactly one signer is passed to the script.\n function signCompact(bytes32 digest) external pure returns (bytes32 r, bytes32 vs);\n\n /// Signs `digest` with signer provided to script using the secp256k1 curve.\n /// Returns a compact signature (`r`, `vs`) as per EIP-2098, where `vs` encodes both the\n /// signature's `s` value, and the recovery id `v` in a single bytes32.\n /// This format reduces the signature size from 65 to 64 bytes.\n /// Raises error if none of the signers passed into the script have provided address.\n function signCompact(address signer, bytes32 digest) external pure returns (bytes32 r, bytes32 vs);\n\n /// Signs `digest` with `privateKey` using the secp256r1 curve.\n function signP256(uint256 privateKey, bytes32 digest) external pure returns (bytes32 r, bytes32 s);\n\n /// Signs data with a `Wallet`.\n function sign(Wallet calldata wallet, bytes32 digest) external returns (uint8 v, bytes32 r, bytes32 s);\n\n /// Signs `digest` with `privateKey` using the secp256k1 curve.\n function sign(uint256 privateKey, bytes32 digest) external pure returns (uint8 v, bytes32 r, bytes32 s);\n\n /// Signs `digest` with signer provided to script using the secp256k1 curve.\n /// If `--sender` is provided, the signer with provided address is used, otherwise,\n /// if exactly one signer is provided to the script, that signer is used.\n /// Raises error if signer passed through `--sender` does not match any unlocked signers or\n /// if `--sender` is not provided and not exactly one signer is passed to the script.\n function sign(bytes32 digest) external pure returns (uint8 v, bytes32 r, bytes32 s);\n\n /// Signs `digest` with signer provided to script using the secp256k1 curve.\n /// Raises error if none of the signers passed into the script have provided address.\n function sign(address signer, bytes32 digest) external pure returns (uint8 v, bytes32 r, bytes32 s);\n\n // ======== Environment ========\n\n /// Gets the environment variable `name` and parses it as `address`.\n /// Reverts if the variable was not found or could not be parsed.\n function envAddress(string calldata name) external view returns (address value);\n\n /// Gets the environment variable `name` and parses it as an array of `address`, delimited by `delim`.\n /// Reverts if the variable was not found or could not be parsed.\n function envAddress(string calldata name, string calldata delim) external view returns (address[] memory value);\n\n /// Gets the environment variable `name` and parses it as `bool`.\n /// Reverts if the variable was not found or could not be parsed.\n function envBool(string calldata name) external view returns (bool value);\n\n /// Gets the environment variable `name` and parses it as an array of `bool`, delimited by `delim`.\n /// Reverts if the variable was not found or could not be parsed.\n function envBool(string calldata name, string calldata delim) external view returns (bool[] memory value);\n\n /// Gets the environment variable `name` and parses it as `bytes32`.\n /// Reverts if the variable was not found or could not be parsed.\n function envBytes32(string calldata name) external view returns (bytes32 value);\n\n /// Gets the environment variable `name` and parses it as an array of `bytes32`, delimited by `delim`.\n /// Reverts if the variable was not found or could not be parsed.\n function envBytes32(string calldata name, string calldata delim) external view returns (bytes32[] memory value);\n\n /// Gets the environment variable `name` and parses it as `bytes`.\n /// Reverts if the variable was not found or could not be parsed.\n function envBytes(string calldata name) external view returns (bytes memory value);\n\n /// Gets the environment variable `name` and parses it as an array of `bytes`, delimited by `delim`.\n /// Reverts if the variable was not found or could not be parsed.\n function envBytes(string calldata name, string calldata delim) external view returns (bytes[] memory value);\n\n /// Gets the environment variable `name` and returns true if it exists, else returns false.\n function envExists(string calldata name) external view returns (bool result);\n\n /// Gets the environment variable `name` and parses it as `int256`.\n /// Reverts if the variable was not found or could not be parsed.\n function envInt(string calldata name) external view returns (int256 value);\n\n /// Gets the environment variable `name` and parses it as an array of `int256`, delimited by `delim`.\n /// Reverts if the variable was not found or could not be parsed.\n function envInt(string calldata name, string calldata delim) external view returns (int256[] memory value);\n\n /// Gets the environment variable `name` and parses it as `bool`.\n /// Reverts if the variable could not be parsed.\n /// Returns `defaultValue` if the variable was not found.\n function envOr(string calldata name, bool defaultValue) external view returns (bool value);\n\n /// Gets the environment variable `name` and parses it as `uint256`.\n /// Reverts if the variable could not be parsed.\n /// Returns `defaultValue` if the variable was not found.\n function envOr(string calldata name, uint256 defaultValue) external view returns (uint256 value);\n\n /// Gets the environment variable `name` and parses it as an array of `address`, delimited by `delim`.\n /// Reverts if the variable could not be parsed.\n /// Returns `defaultValue` if the variable was not found.\n function envOr(string calldata name, string calldata delim, address[] calldata defaultValue)\n external\n view\n returns (address[] memory value);\n\n /// Gets the environment variable `name` and parses it as an array of `bytes32`, delimited by `delim`.\n /// Reverts if the variable could not be parsed.\n /// Returns `defaultValue` if the variable was not found.\n function envOr(string calldata name, string calldata delim, bytes32[] calldata defaultValue)\n external\n view\n returns (bytes32[] memory value);\n\n /// Gets the environment variable `name` and parses it as an array of `string`, delimited by `delim`.\n /// Reverts if the variable could not be parsed.\n /// Returns `defaultValue` if the variable was not found.\n function envOr(string calldata name, string calldata delim, string[] calldata defaultValue)\n external\n view\n returns (string[] memory value);\n\n /// Gets the environment variable `name` and parses it as an array of `bytes`, delimited by `delim`.\n /// Reverts if the variable could not be parsed.\n /// Returns `defaultValue` if the variable was not found.\n function envOr(string calldata name, string calldata delim, bytes[] calldata defaultValue)\n external\n view\n returns (bytes[] memory value);\n\n /// Gets the environment variable `name` and parses it as `int256`.\n /// Reverts if the variable could not be parsed.\n /// Returns `defaultValue` if the variable was not found.\n function envOr(string calldata name, int256 defaultValue) external view returns (int256 value);\n\n /// Gets the environment variable `name` and parses it as `address`.\n /// Reverts if the variable could not be parsed.\n /// Returns `defaultValue` if the variable was not found.\n function envOr(string calldata name, address defaultValue) external view returns (address value);\n\n /// Gets the environment variable `name` and parses it as `bytes32`.\n /// Reverts if the variable could not be parsed.\n /// Returns `defaultValue` if the variable was not found.\n function envOr(string calldata name, bytes32 defaultValue) external view returns (bytes32 value);\n\n /// Gets the environment variable `name` and parses it as `string`.\n /// Reverts if the variable could not be parsed.\n /// Returns `defaultValue` if the variable was not found.\n function envOr(string calldata name, string calldata defaultValue) external view returns (string memory value);\n\n /// Gets the environment variable `name` and parses it as `bytes`.\n /// Reverts if the variable could not be parsed.\n /// Returns `defaultValue` if the variable was not found.\n function envOr(string calldata name, bytes calldata defaultValue) external view returns (bytes memory value);\n\n /// Gets the environment variable `name` and parses it as an array of `bool`, delimited by `delim`.\n /// Reverts if the variable could not be parsed.\n /// Returns `defaultValue` if the variable was not found.\n function envOr(string calldata name, string calldata delim, bool[] calldata defaultValue)\n external\n view\n returns (bool[] memory value);\n\n /// Gets the environment variable `name` and parses it as an array of `uint256`, delimited by `delim`.\n /// Reverts if the variable could not be parsed.\n /// Returns `defaultValue` if the variable was not found.\n function envOr(string calldata name, string calldata delim, uint256[] calldata defaultValue)\n external\n view\n returns (uint256[] memory value);\n\n /// Gets the environment variable `name` and parses it as an array of `int256`, delimited by `delim`.\n /// Reverts if the variable could not be parsed.\n /// Returns `defaultValue` if the variable was not found.\n function envOr(string calldata name, string calldata delim, int256[] calldata defaultValue)\n external\n view\n returns (int256[] memory value);\n\n /// Gets the environment variable `name` and parses it as `string`.\n /// Reverts if the variable was not found or could not be parsed.\n function envString(string calldata name) external view returns (string memory value);\n\n /// Gets the environment variable `name` and parses it as an array of `string`, delimited by `delim`.\n /// Reverts if the variable was not found or could not be parsed.\n function envString(string calldata name, string calldata delim) external view returns (string[] memory value);\n\n /// Gets the environment variable `name` and parses it as `uint256`.\n /// Reverts if the variable was not found or could not be parsed.\n function envUint(string calldata name) external view returns (uint256 value);\n\n /// Gets the environment variable `name` and parses it as an array of `uint256`, delimited by `delim`.\n /// Reverts if the variable was not found or could not be parsed.\n function envUint(string calldata name, string calldata delim) external view returns (uint256[] memory value);\n\n /// Returns true if `forge` command was executed in given context.\n function isContext(ForgeContext context) external view returns (bool result);\n\n /// Sets environment variables.\n function setEnv(string calldata name, string calldata value) external;\n\n // ======== EVM ========\n\n /// Gets all accessed reads and write slot from a `vm.record` session, for a given address.\n function accesses(address target) external returns (bytes32[] memory readSlots, bytes32[] memory writeSlots);\n\n /// Gets the address for a given private key.\n function addr(uint256 privateKey) external pure returns (address keyAddr);\n\n /// Gets all the logs according to specified filter.\n function eth_getLogs(uint256 fromBlock, uint256 toBlock, address target, bytes32[] calldata topics)\n external\n returns (EthGetLogs[] memory logs);\n\n /// Gets the current `block.blobbasefee`.\n /// You should use this instead of `block.blobbasefee` if you use `vm.blobBaseFee`, as `block.blobbasefee` is assumed to be constant across a transaction,\n /// and as a result will get optimized out by the compiler.\n /// See https://github.com/foundry-rs/foundry/issues/6180\n function getBlobBaseFee() external view returns (uint256 blobBaseFee);\n\n /// Gets the current `block.number`.\n /// You should use this instead of `block.number` if you use `vm.roll`, as `block.number` is assumed to be constant across a transaction,\n /// and as a result will get optimized out by the compiler.\n /// See https://github.com/foundry-rs/foundry/issues/6180\n function getBlockNumber() external view returns (uint256 height);\n\n /// Gets the current `block.timestamp`.\n /// You should use this instead of `block.timestamp` if you use `vm.warp`, as `block.timestamp` is assumed to be constant across a transaction,\n /// and as a result will get optimized out by the compiler.\n /// See https://github.com/foundry-rs/foundry/issues/6180\n function getBlockTimestamp() external view returns (uint256 timestamp);\n\n /// Gets the map key and parent of a mapping at a given slot, for a given address.\n function getMappingKeyAndParentOf(address target, bytes32 elementSlot)\n external\n returns (bool found, bytes32 key, bytes32 parent);\n\n /// Gets the number of elements in the mapping at the given slot, for a given address.\n function getMappingLength(address target, bytes32 mappingSlot) external returns (uint256 length);\n\n /// Gets the elements at index idx of the mapping at the given slot, for a given address. The\n /// index must be less than the length of the mapping (i.e. the number of keys in the mapping).\n function getMappingSlotAt(address target, bytes32 mappingSlot, uint256 idx) external returns (bytes32 value);\n\n /// Gets the nonce of an account.\n function getNonce(address account) external view returns (uint64 nonce);\n\n /// Get the nonce of a `Wallet`.\n function getNonce(Wallet calldata wallet) external returns (uint64 nonce);\n\n /// Gets all the recorded logs.\n function getRecordedLogs() external returns (Log[] memory logs);\n\n /// Returns state diffs from current `vm.startStateDiffRecording` session.\n function getStateDiff() external view returns (string memory diff);\n\n /// Returns state diffs from current `vm.startStateDiffRecording` session, in json format.\n function getStateDiffJson() external view returns (string memory diff);\n\n /// Gets the gas used in the last call from the callee perspective.\n function lastCallGas() external view returns (Gas memory gas);\n\n /// Loads a storage slot from an address.\n function load(address target, bytes32 slot) external view returns (bytes32 data);\n\n /// Pauses gas metering (i.e. gas usage is not counted). Noop if already paused.\n function pauseGasMetering() external;\n\n /// Records all storage reads and writes.\n function record() external;\n\n /// Record all the transaction logs.\n function recordLogs() external;\n\n /// Reset gas metering (i.e. gas usage is set to gas limit).\n function resetGasMetering() external;\n\n /// Resumes gas metering (i.e. gas usage is counted again). Noop if already on.\n function resumeGasMetering() external;\n\n /// Performs an Ethereum JSON-RPC request to the current fork URL.\n function rpc(string calldata method, string calldata params) external returns (bytes memory data);\n\n /// Performs an Ethereum JSON-RPC request to the given endpoint.\n function rpc(string calldata urlOrAlias, string calldata method, string calldata params)\n external\n returns (bytes memory data);\n\n /// Records the debug trace during the run.\n function startDebugTraceRecording() external;\n\n /// Starts recording all map SSTOREs for later retrieval.\n function startMappingRecording() external;\n\n /// Record all account accesses as part of CREATE, CALL or SELFDESTRUCT opcodes in order,\n /// along with the context of the calls\n function startStateDiffRecording() external;\n\n /// Stop debug trace recording and returns the recorded debug trace.\n function stopAndReturnDebugTraceRecording() external returns (DebugStep[] memory step);\n\n /// Returns an ordered array of all account accesses from a `vm.startStateDiffRecording` session.\n function stopAndReturnStateDiff() external returns (AccountAccess[] memory accountAccesses);\n\n /// Stops recording all map SSTOREs for later retrieval and clears the recorded data.\n function stopMappingRecording() external;\n\n // ======== Filesystem ========\n\n /// Closes file for reading, resetting the offset and allowing to read it from beginning with readLine.\n /// `path` is relative to the project root.\n function closeFile(string calldata path) external;\n\n /// Copies the contents of one file to another. This function will **overwrite** the contents of `to`.\n /// On success, the total number of bytes copied is returned and it is equal to the length of the `to` file as reported by `metadata`.\n /// Both `from` and `to` are relative to the project root.\n function copyFile(string calldata from, string calldata to) external returns (uint64 copied);\n\n /// Creates a new, empty directory at the provided path.\n /// This cheatcode will revert in the following situations, but is not limited to just these cases:\n /// - User lacks permissions to modify `path`.\n /// - A parent of the given path doesn't exist and `recursive` is false.\n /// - `path` already exists and `recursive` is false.\n /// `path` is relative to the project root.\n function createDir(string calldata path, bool recursive) external;\n\n /// Deploys a contract from an artifact file. Takes in the relative path to the json file or the path to the\n /// artifact in the form of :: where and parts are optional.\n function deployCode(string calldata artifactPath) external returns (address deployedAddress);\n\n /// Deploys a contract from an artifact file. Takes in the relative path to the json file or the path to the\n /// artifact in the form of :: where and parts are optional.\n /// Additionally accepts abi-encoded constructor arguments.\n function deployCode(string calldata artifactPath, bytes calldata constructorArgs)\n external\n returns (address deployedAddress);\n\n /// Returns true if the given path points to an existing entity, else returns false.\n function exists(string calldata path) external view returns (bool result);\n\n /// Performs a foreign function call via the terminal.\n function ffi(string[] calldata commandInput) external returns (bytes memory result);\n\n /// Given a path, query the file system to get information about a file, directory, etc.\n function fsMetadata(string calldata path) external view returns (FsMetadata memory metadata);\n\n /// Gets the artifact path from code (aka. creation code).\n function getArtifactPathByCode(bytes calldata code) external view returns (string memory path);\n\n /// Gets the artifact path from deployed code (aka. runtime code).\n function getArtifactPathByDeployedCode(bytes calldata deployedCode) external view returns (string memory path);\n\n /// Returns the most recent broadcast for the given contract on `chainId` matching `txType`.\n /// For example:\n /// The most recent deployment can be fetched by passing `txType` as `CREATE` or `CREATE2`.\n /// The most recent call can be fetched by passing `txType` as `CALL`.\n function getBroadcast(string calldata contractName, uint64 chainId, BroadcastTxType txType)\n external\n view\n returns (BroadcastTxSummary memory);\n\n /// Returns all broadcasts for the given contract on `chainId` with the specified `txType`.\n /// Sorted such that the most recent broadcast is the first element, and the oldest is the last. i.e descending order of BroadcastTxSummary.blockNumber.\n function getBroadcasts(string calldata contractName, uint64 chainId, BroadcastTxType txType)\n external\n view\n returns (BroadcastTxSummary[] memory);\n\n /// Returns all broadcasts for the given contract on `chainId`.\n /// Sorted such that the most recent broadcast is the first element, and the oldest is the last. i.e descending order of BroadcastTxSummary.blockNumber.\n function getBroadcasts(string calldata contractName, uint64 chainId)\n external\n view\n returns (BroadcastTxSummary[] memory);\n\n /// Gets the creation bytecode from an artifact file. Takes in the relative path to the json file or the path to the\n /// artifact in the form of :: where and parts are optional.\n function getCode(string calldata artifactPath) external view returns (bytes memory creationBytecode);\n\n /// Gets the deployed bytecode from an artifact file. Takes in the relative path to the json file or the path to the\n /// artifact in the form of :: where and parts are optional.\n function getDeployedCode(string calldata artifactPath) external view returns (bytes memory runtimeBytecode);\n\n /// Returns the most recent deployment for the current `chainId`.\n function getDeployment(string calldata contractName) external view returns (address deployedAddress);\n\n /// Returns the most recent deployment for the given contract on `chainId`\n function getDeployment(string calldata contractName, uint64 chainId)\n external\n view\n returns (address deployedAddress);\n\n /// Returns all deployments for the given contract on `chainId`\n /// Sorted in descending order of deployment time i.e descending order of BroadcastTxSummary.blockNumber.\n /// The most recent deployment is the first element, and the oldest is the last.\n function getDeployments(string calldata contractName, uint64 chainId)\n external\n view\n returns (address[] memory deployedAddresses);\n\n /// Returns true if the path exists on disk and is pointing at a directory, else returns false.\n function isDir(string calldata path) external view returns (bool result);\n\n /// Returns true if the path exists on disk and is pointing at a regular file, else returns false.\n function isFile(string calldata path) external view returns (bool result);\n\n /// Get the path of the current project root.\n function projectRoot() external view returns (string memory path);\n\n /// Prompts the user for a string value in the terminal.\n function prompt(string calldata promptText) external returns (string memory input);\n\n /// Prompts the user for an address in the terminal.\n function promptAddress(string calldata promptText) external returns (address);\n\n /// Prompts the user for a hidden string value in the terminal.\n function promptSecret(string calldata promptText) external returns (string memory input);\n\n /// Prompts the user for hidden uint256 in the terminal (usually pk).\n function promptSecretUint(string calldata promptText) external returns (uint256);\n\n /// Prompts the user for uint256 in the terminal.\n function promptUint(string calldata promptText) external returns (uint256);\n\n /// Reads the directory at the given path recursively, up to `maxDepth`.\n /// `maxDepth` defaults to 1, meaning only the direct children of the given directory will be returned.\n /// Follows symbolic links if `followLinks` is true.\n function readDir(string calldata path) external view returns (DirEntry[] memory entries);\n\n /// See `readDir(string)`.\n function readDir(string calldata path, uint64 maxDepth) external view returns (DirEntry[] memory entries);\n\n /// See `readDir(string)`.\n function readDir(string calldata path, uint64 maxDepth, bool followLinks)\n external\n view\n returns (DirEntry[] memory entries);\n\n /// Reads the entire content of file to string. `path` is relative to the project root.\n function readFile(string calldata path) external view returns (string memory data);\n\n /// Reads the entire content of file as binary. `path` is relative to the project root.\n function readFileBinary(string calldata path) external view returns (bytes memory data);\n\n /// Reads next line of file to string.\n function readLine(string calldata path) external view returns (string memory line);\n\n /// Reads a symbolic link, returning the path that the link points to.\n /// This cheatcode will revert in the following situations, but is not limited to just these cases:\n /// - `path` is not a symbolic link.\n /// - `path` does not exist.\n function readLink(string calldata linkPath) external view returns (string memory targetPath);\n\n /// Removes a directory at the provided path.\n /// This cheatcode will revert in the following situations, but is not limited to just these cases:\n /// - `path` doesn't exist.\n /// - `path` isn't a directory.\n /// - User lacks permissions to modify `path`.\n /// - The directory is not empty and `recursive` is false.\n /// `path` is relative to the project root.\n function removeDir(string calldata path, bool recursive) external;\n\n /// Removes a file from the filesystem.\n /// This cheatcode will revert in the following situations, but is not limited to just these cases:\n /// - `path` points to a directory.\n /// - The file doesn't exist.\n /// - The user lacks permissions to remove the file.\n /// `path` is relative to the project root.\n function removeFile(string calldata path) external;\n\n /// Performs a foreign function call via terminal and returns the exit code, stdout, and stderr.\n function tryFfi(string[] calldata commandInput) external returns (FfiResult memory result);\n\n /// Returns the time since unix epoch in milliseconds.\n function unixTime() external view returns (uint256 milliseconds);\n\n /// Writes data to file, creating a file if it does not exist, and entirely replacing its contents if it does.\n /// `path` is relative to the project root.\n function writeFile(string calldata path, string calldata data) external;\n\n /// Writes binary data to a file, creating a file if it does not exist, and entirely replacing its contents if it does.\n /// `path` is relative to the project root.\n function writeFileBinary(string calldata path, bytes calldata data) external;\n\n /// Writes line to file, creating a file if it does not exist.\n /// `path` is relative to the project root.\n function writeLine(string calldata path, string calldata data) external;\n\n // ======== JSON ========\n\n /// Checks if `key` exists in a JSON object.\n function keyExistsJson(string calldata json, string calldata key) external view returns (bool);\n\n /// Parses a string of JSON data at `key` and coerces it to `address`.\n function parseJsonAddress(string calldata json, string calldata key) external pure returns (address);\n\n /// Parses a string of JSON data at `key` and coerces it to `address[]`.\n function parseJsonAddressArray(string calldata json, string calldata key)\n external\n pure\n returns (address[] memory);\n\n /// Parses a string of JSON data at `key` and coerces it to `bool`.\n function parseJsonBool(string calldata json, string calldata key) external pure returns (bool);\n\n /// Parses a string of JSON data at `key` and coerces it to `bool[]`.\n function parseJsonBoolArray(string calldata json, string calldata key) external pure returns (bool[] memory);\n\n /// Parses a string of JSON data at `key` and coerces it to `bytes`.\n function parseJsonBytes(string calldata json, string calldata key) external pure returns (bytes memory);\n\n /// Parses a string of JSON data at `key` and coerces it to `bytes32`.\n function parseJsonBytes32(string calldata json, string calldata key) external pure returns (bytes32);\n\n /// Parses a string of JSON data at `key` and coerces it to `bytes32[]`.\n function parseJsonBytes32Array(string calldata json, string calldata key)\n external\n pure\n returns (bytes32[] memory);\n\n /// Parses a string of JSON data at `key` and coerces it to `bytes[]`.\n function parseJsonBytesArray(string calldata json, string calldata key) external pure returns (bytes[] memory);\n\n /// Parses a string of JSON data at `key` and coerces it to `int256`.\n function parseJsonInt(string calldata json, string calldata key) external pure returns (int256);\n\n /// Parses a string of JSON data at `key` and coerces it to `int256[]`.\n function parseJsonIntArray(string calldata json, string calldata key) external pure returns (int256[] memory);\n\n /// Returns an array of all the keys in a JSON object.\n function parseJsonKeys(string calldata json, string calldata key) external pure returns (string[] memory keys);\n\n /// Parses a string of JSON data at `key` and coerces it to `string`.\n function parseJsonString(string calldata json, string calldata key) external pure returns (string memory);\n\n /// Parses a string of JSON data at `key` and coerces it to `string[]`.\n function parseJsonStringArray(string calldata json, string calldata key) external pure returns (string[] memory);\n\n /// Parses a string of JSON data at `key` and coerces it to type array corresponding to `typeDescription`.\n function parseJsonTypeArray(string calldata json, string calldata key, string calldata typeDescription)\n external\n pure\n returns (bytes memory);\n\n /// Parses a string of JSON data and coerces it to type corresponding to `typeDescription`.\n function parseJsonType(string calldata json, string calldata typeDescription)\n external\n pure\n returns (bytes memory);\n\n /// Parses a string of JSON data at `key` and coerces it to type corresponding to `typeDescription`.\n function parseJsonType(string calldata json, string calldata key, string calldata typeDescription)\n external\n pure\n returns (bytes memory);\n\n /// Parses a string of JSON data at `key` and coerces it to `uint256`.\n function parseJsonUint(string calldata json, string calldata key) external pure returns (uint256);\n\n /// Parses a string of JSON data at `key` and coerces it to `uint256[]`.\n function parseJsonUintArray(string calldata json, string calldata key) external pure returns (uint256[] memory);\n\n /// ABI-encodes a JSON object.\n function parseJson(string calldata json) external pure returns (bytes memory abiEncodedData);\n\n /// ABI-encodes a JSON object at `key`.\n function parseJson(string calldata json, string calldata key) external pure returns (bytes memory abiEncodedData);\n\n /// See `serializeJson`.\n function serializeAddress(string calldata objectKey, string calldata valueKey, address value)\n external\n returns (string memory json);\n\n /// See `serializeJson`.\n function serializeAddress(string calldata objectKey, string calldata valueKey, address[] calldata values)\n external\n returns (string memory json);\n\n /// See `serializeJson`.\n function serializeBool(string calldata objectKey, string calldata valueKey, bool value)\n external\n returns (string memory json);\n\n /// See `serializeJson`.\n function serializeBool(string calldata objectKey, string calldata valueKey, bool[] calldata values)\n external\n returns (string memory json);\n\n /// See `serializeJson`.\n function serializeBytes32(string calldata objectKey, string calldata valueKey, bytes32 value)\n external\n returns (string memory json);\n\n /// See `serializeJson`.\n function serializeBytes32(string calldata objectKey, string calldata valueKey, bytes32[] calldata values)\n external\n returns (string memory json);\n\n /// See `serializeJson`.\n function serializeBytes(string calldata objectKey, string calldata valueKey, bytes calldata value)\n external\n returns (string memory json);\n\n /// See `serializeJson`.\n function serializeBytes(string calldata objectKey, string calldata valueKey, bytes[] calldata values)\n external\n returns (string memory json);\n\n /// See `serializeJson`.\n function serializeInt(string calldata objectKey, string calldata valueKey, int256 value)\n external\n returns (string memory json);\n\n /// See `serializeJson`.\n function serializeInt(string calldata objectKey, string calldata valueKey, int256[] calldata values)\n external\n returns (string memory json);\n\n /// Serializes a key and value to a JSON object stored in-memory that can be later written to a file.\n /// Returns the stringified version of the specific JSON file up to that moment.\n function serializeJson(string calldata objectKey, string calldata value) external returns (string memory json);\n\n /// See `serializeJson`.\n function serializeJsonType(string calldata typeDescription, bytes calldata value)\n external\n pure\n returns (string memory json);\n\n /// See `serializeJson`.\n function serializeJsonType(\n string calldata objectKey,\n string calldata valueKey,\n string calldata typeDescription,\n bytes calldata value\n ) external returns (string memory json);\n\n /// See `serializeJson`.\n function serializeString(string calldata objectKey, string calldata valueKey, string calldata value)\n external\n returns (string memory json);\n\n /// See `serializeJson`.\n function serializeString(string calldata objectKey, string calldata valueKey, string[] calldata values)\n external\n returns (string memory json);\n\n /// See `serializeJson`.\n function serializeUintToHex(string calldata objectKey, string calldata valueKey, uint256 value)\n external\n returns (string memory json);\n\n /// See `serializeJson`.\n function serializeUint(string calldata objectKey, string calldata valueKey, uint256 value)\n external\n returns (string memory json);\n\n /// See `serializeJson`.\n function serializeUint(string calldata objectKey, string calldata valueKey, uint256[] calldata values)\n external\n returns (string memory json);\n\n /// Write a serialized JSON object to a file. If the file exists, it will be overwritten.\n function writeJson(string calldata json, string calldata path) external;\n\n /// Write a serialized JSON object to an **existing** JSON file, replacing a value with key = \n /// This is useful to replace a specific value of a JSON file, without having to parse the entire thing.\n function writeJson(string calldata json, string calldata path, string calldata valueKey) external;\n\n /// Checks if `key` exists in a JSON object\n /// `keyExists` is being deprecated in favor of `keyExistsJson`. It will be removed in future versions.\n function keyExists(string calldata json, string calldata key) external view returns (bool);\n\n // ======== Scripting ========\n\n /// Designate the next call as an EIP-7702 transaction\n function attachDelegation(SignedDelegation calldata signedDelegation) external;\n\n /// Takes a signed transaction and broadcasts it to the network.\n function broadcastRawTransaction(bytes calldata data) external;\n\n /// Has the next call (at this call depth only) create transactions that can later be signed and sent onchain.\n /// Broadcasting address is determined by checking the following in order:\n /// 1. If `--sender` argument was provided, that address is used.\n /// 2. If exactly one signer (e.g. private key, hw wallet, keystore) is set when `forge broadcast` is invoked, that signer is used.\n /// 3. Otherwise, default foundry sender (1804c8AB1F12E6bbf3894d4083f33e07309d1f38) is used.\n function broadcast() external;\n\n /// Has the next call (at this call depth only) create a transaction with the address provided\n /// as the sender that can later be signed and sent onchain.\n function broadcast(address signer) external;\n\n /// Has the next call (at this call depth only) create a transaction with the private key\n /// provided as the sender that can later be signed and sent onchain.\n function broadcast(uint256 privateKey) external;\n\n /// Returns addresses of available unlocked wallets in the script environment.\n function getWallets() external returns (address[] memory wallets);\n\n /// Sign an EIP-7702 authorization and designate the next call as an EIP-7702 transaction\n function signAndAttachDelegation(address implementation, uint256 privateKey)\n external\n returns (SignedDelegation memory signedDelegation);\n\n /// Sign an EIP-7702 authorization for delegation\n function signDelegation(address implementation, uint256 privateKey)\n external\n returns (SignedDelegation memory signedDelegation);\n\n /// Has all subsequent calls (at this call depth only) create transactions that can later be signed and sent onchain.\n /// Broadcasting address is determined by checking the following in order:\n /// 1. If `--sender` argument was provided, that address is used.\n /// 2. If exactly one signer (e.g. private key, hw wallet, keystore) is set when `forge broadcast` is invoked, that signer is used.\n /// 3. Otherwise, default foundry sender (1804c8AB1F12E6bbf3894d4083f33e07309d1f38) is used.\n function startBroadcast() external;\n\n /// Has all subsequent calls (at this call depth only) create transactions with the address\n /// provided that can later be signed and sent onchain.\n function startBroadcast(address signer) external;\n\n /// Has all subsequent calls (at this call depth only) create transactions with the private key\n /// provided that can later be signed and sent onchain.\n function startBroadcast(uint256 privateKey) external;\n\n /// Stops collecting onchain transactions.\n function stopBroadcast() external;\n\n // ======== String ========\n\n /// Returns true if `search` is found in `subject`, false otherwise.\n function contains(string calldata subject, string calldata search) external returns (bool result);\n\n /// Returns the index of the first occurrence of a `key` in an `input` string.\n /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `key` is not found.\n /// Returns 0 in case of an empty `key`.\n function indexOf(string calldata input, string calldata key) external pure returns (uint256);\n\n /// Parses the given `string` into an `address`.\n function parseAddress(string calldata stringifiedValue) external pure returns (address parsedValue);\n\n /// Parses the given `string` into a `bool`.\n function parseBool(string calldata stringifiedValue) external pure returns (bool parsedValue);\n\n /// Parses the given `string` into `bytes`.\n function parseBytes(string calldata stringifiedValue) external pure returns (bytes memory parsedValue);\n\n /// Parses the given `string` into a `bytes32`.\n function parseBytes32(string calldata stringifiedValue) external pure returns (bytes32 parsedValue);\n\n /// Parses the given `string` into a `int256`.\n function parseInt(string calldata stringifiedValue) external pure returns (int256 parsedValue);\n\n /// Parses the given `string` into a `uint256`.\n function parseUint(string calldata stringifiedValue) external pure returns (uint256 parsedValue);\n\n /// Replaces occurrences of `from` in the given `string` with `to`.\n function replace(string calldata input, string calldata from, string calldata to)\n external\n pure\n returns (string memory output);\n\n /// Splits the given `string` into an array of strings divided by the `delimiter`.\n function split(string calldata input, string calldata delimiter) external pure returns (string[] memory outputs);\n\n /// Converts the given `string` value to Lowercase.\n function toLowercase(string calldata input) external pure returns (string memory output);\n\n /// Converts the given value to a `string`.\n function toString(address value) external pure returns (string memory stringifiedValue);\n\n /// Converts the given value to a `string`.\n function toString(bytes calldata value) external pure returns (string memory stringifiedValue);\n\n /// Converts the given value to a `string`.\n function toString(bytes32 value) external pure returns (string memory stringifiedValue);\n\n /// Converts the given value to a `string`.\n function toString(bool value) external pure returns (string memory stringifiedValue);\n\n /// Converts the given value to a `string`.\n function toString(uint256 value) external pure returns (string memory stringifiedValue);\n\n /// Converts the given value to a `string`.\n function toString(int256 value) external pure returns (string memory stringifiedValue);\n\n /// Converts the given `string` value to Uppercase.\n function toUppercase(string calldata input) external pure returns (string memory output);\n\n /// Trims leading and trailing whitespace from the given `string` value.\n function trim(string calldata input) external pure returns (string memory output);\n\n // ======== Testing ========\n\n /// Compares two `uint256` values. Expects difference to be less than or equal to `maxDelta`.\n /// Formats values with decimals in failure message.\n function assertApproxEqAbsDecimal(uint256 left, uint256 right, uint256 maxDelta, uint256 decimals) external pure;\n\n /// Compares two `uint256` values. Expects difference to be less than or equal to `maxDelta`.\n /// Formats values with decimals in failure message. Includes error message into revert string on failure.\n function assertApproxEqAbsDecimal(\n uint256 left,\n uint256 right,\n uint256 maxDelta,\n uint256 decimals,\n string calldata error\n ) external pure;\n\n /// Compares two `int256` values. Expects difference to be less than or equal to `maxDelta`.\n /// Formats values with decimals in failure message.\n function assertApproxEqAbsDecimal(int256 left, int256 right, uint256 maxDelta, uint256 decimals) external pure;\n\n /// Compares two `int256` values. Expects difference to be less than or equal to `maxDelta`.\n /// Formats values with decimals in failure message. Includes error message into revert string on failure.\n function assertApproxEqAbsDecimal(\n int256 left,\n int256 right,\n uint256 maxDelta,\n uint256 decimals,\n string calldata error\n ) external pure;\n\n /// Compares two `uint256` values. Expects difference to be less than or equal to `maxDelta`.\n function assertApproxEqAbs(uint256 left, uint256 right, uint256 maxDelta) external pure;\n\n /// Compares two `uint256` values. Expects difference to be less than or equal to `maxDelta`.\n /// Includes error message into revert string on failure.\n function assertApproxEqAbs(uint256 left, uint256 right, uint256 maxDelta, string calldata error) external pure;\n\n /// Compares two `int256` values. Expects difference to be less than or equal to `maxDelta`.\n function assertApproxEqAbs(int256 left, int256 right, uint256 maxDelta) external pure;\n\n /// Compares two `int256` values. Expects difference to be less than or equal to `maxDelta`.\n /// Includes error message into revert string on failure.\n function assertApproxEqAbs(int256 left, int256 right, uint256 maxDelta, string calldata error) external pure;\n\n /// Compares two `uint256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`.\n /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100%\n /// Formats values with decimals in failure message.\n function assertApproxEqRelDecimal(uint256 left, uint256 right, uint256 maxPercentDelta, uint256 decimals)\n external\n pure;\n\n /// Compares two `uint256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`.\n /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100%\n /// Formats values with decimals in failure message. Includes error message into revert string on failure.\n function assertApproxEqRelDecimal(\n uint256 left,\n uint256 right,\n uint256 maxPercentDelta,\n uint256 decimals,\n string calldata error\n ) external pure;\n\n /// Compares two `int256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`.\n /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100%\n /// Formats values with decimals in failure message.\n function assertApproxEqRelDecimal(int256 left, int256 right, uint256 maxPercentDelta, uint256 decimals)\n external\n pure;\n\n /// Compares two `int256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`.\n /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100%\n /// Formats values with decimals in failure message. Includes error message into revert string on failure.\n function assertApproxEqRelDecimal(\n int256 left,\n int256 right,\n uint256 maxPercentDelta,\n uint256 decimals,\n string calldata error\n ) external pure;\n\n /// Compares two `uint256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`.\n /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100%\n function assertApproxEqRel(uint256 left, uint256 right, uint256 maxPercentDelta) external pure;\n\n /// Compares two `uint256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`.\n /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100%\n /// Includes error message into revert string on failure.\n function assertApproxEqRel(uint256 left, uint256 right, uint256 maxPercentDelta, string calldata error)\n external\n pure;\n\n /// Compares two `int256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`.\n /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100%\n function assertApproxEqRel(int256 left, int256 right, uint256 maxPercentDelta) external pure;\n\n /// Compares two `int256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`.\n /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100%\n /// Includes error message into revert string on failure.\n function assertApproxEqRel(int256 left, int256 right, uint256 maxPercentDelta, string calldata error)\n external\n pure;\n\n /// Asserts that two `uint256` values are equal, formatting them with decimals in failure message.\n function assertEqDecimal(uint256 left, uint256 right, uint256 decimals) external pure;\n\n /// Asserts that two `uint256` values are equal, formatting them with decimals in failure message.\n /// Includes error message into revert string on failure.\n function assertEqDecimal(uint256 left, uint256 right, uint256 decimals, string calldata error) external pure;\n\n /// Asserts that two `int256` values are equal, formatting them with decimals in failure message.\n function assertEqDecimal(int256 left, int256 right, uint256 decimals) external pure;\n\n /// Asserts that two `int256` values are equal, formatting them with decimals in failure message.\n /// Includes error message into revert string on failure.\n function assertEqDecimal(int256 left, int256 right, uint256 decimals, string calldata error) external pure;\n\n /// Asserts that two `bool` values are equal.\n function assertEq(bool left, bool right) external pure;\n\n /// Asserts that two `bool` values are equal and includes error message into revert string on failure.\n function assertEq(bool left, bool right, string calldata error) external pure;\n\n /// Asserts that two `string` values are equal.\n function assertEq(string calldata left, string calldata right) external pure;\n\n /// Asserts that two `string` values are equal and includes error message into revert string on failure.\n function assertEq(string calldata left, string calldata right, string calldata error) external pure;\n\n /// Asserts that two `bytes` values are equal.\n function assertEq(bytes calldata left, bytes calldata right) external pure;\n\n /// Asserts that two `bytes` values are equal and includes error message into revert string on failure.\n function assertEq(bytes calldata left, bytes calldata right, string calldata error) external pure;\n\n /// Asserts that two arrays of `bool` values are equal.\n function assertEq(bool[] calldata left, bool[] calldata right) external pure;\n\n /// Asserts that two arrays of `bool` values are equal and includes error message into revert string on failure.\n function assertEq(bool[] calldata left, bool[] calldata right, string calldata error) external pure;\n\n /// Asserts that two arrays of `uint256 values are equal.\n function assertEq(uint256[] calldata left, uint256[] calldata right) external pure;\n\n /// Asserts that two arrays of `uint256` values are equal and includes error message into revert string on failure.\n function assertEq(uint256[] calldata left, uint256[] calldata right, string calldata error) external pure;\n\n /// Asserts that two arrays of `int256` values are equal.\n function assertEq(int256[] calldata left, int256[] calldata right) external pure;\n\n /// Asserts that two arrays of `int256` values are equal and includes error message into revert string on failure.\n function assertEq(int256[] calldata left, int256[] calldata right, string calldata error) external pure;\n\n /// Asserts that two `uint256` values are equal.\n function assertEq(uint256 left, uint256 right) external pure;\n\n /// Asserts that two arrays of `address` values are equal.\n function assertEq(address[] calldata left, address[] calldata right) external pure;\n\n /// Asserts that two arrays of `address` values are equal and includes error message into revert string on failure.\n function assertEq(address[] calldata left, address[] calldata right, string calldata error) external pure;\n\n /// Asserts that two arrays of `bytes32` values are equal.\n function assertEq(bytes32[] calldata left, bytes32[] calldata right) external pure;\n\n /// Asserts that two arrays of `bytes32` values are equal and includes error message into revert string on failure.\n function assertEq(bytes32[] calldata left, bytes32[] calldata right, string calldata error) external pure;\n\n /// Asserts that two arrays of `string` values are equal.\n function assertEq(string[] calldata left, string[] calldata right) external pure;\n\n /// Asserts that two arrays of `string` values are equal and includes error message into revert string on failure.\n function assertEq(string[] calldata left, string[] calldata right, string calldata error) external pure;\n\n /// Asserts that two arrays of `bytes` values are equal.\n function assertEq(bytes[] calldata left, bytes[] calldata right) external pure;\n\n /// Asserts that two arrays of `bytes` values are equal and includes error message into revert string on failure.\n function assertEq(bytes[] calldata left, bytes[] calldata right, string calldata error) external pure;\n\n /// Asserts that two `uint256` values are equal and includes error message into revert string on failure.\n function assertEq(uint256 left, uint256 right, string calldata error) external pure;\n\n /// Asserts that two `int256` values are equal.\n function assertEq(int256 left, int256 right) external pure;\n\n /// Asserts that two `int256` values are equal and includes error message into revert string on failure.\n function assertEq(int256 left, int256 right, string calldata error) external pure;\n\n /// Asserts that two `address` values are equal.\n function assertEq(address left, address right) external pure;\n\n /// Asserts that two `address` values are equal and includes error message into revert string on failure.\n function assertEq(address left, address right, string calldata error) external pure;\n\n /// Asserts that two `bytes32` values are equal.\n function assertEq(bytes32 left, bytes32 right) external pure;\n\n /// Asserts that two `bytes32` values are equal and includes error message into revert string on failure.\n function assertEq(bytes32 left, bytes32 right, string calldata error) external pure;\n\n /// Asserts that the given condition is false.\n function assertFalse(bool condition) external pure;\n\n /// Asserts that the given condition is false and includes error message into revert string on failure.\n function assertFalse(bool condition, string calldata error) external pure;\n\n /// Compares two `uint256` values. Expects first value to be greater than or equal to second.\n /// Formats values with decimals in failure message.\n function assertGeDecimal(uint256 left, uint256 right, uint256 decimals) external pure;\n\n /// Compares two `uint256` values. Expects first value to be greater than or equal to second.\n /// Formats values with decimals in failure message. Includes error message into revert string on failure.\n function assertGeDecimal(uint256 left, uint256 right, uint256 decimals, string calldata error) external pure;\n\n /// Compares two `int256` values. Expects first value to be greater than or equal to second.\n /// Formats values with decimals in failure message.\n function assertGeDecimal(int256 left, int256 right, uint256 decimals) external pure;\n\n /// Compares two `int256` values. Expects first value to be greater than or equal to second.\n /// Formats values with decimals in failure message. Includes error message into revert string on failure.\n function assertGeDecimal(int256 left, int256 right, uint256 decimals, string calldata error) external pure;\n\n /// Compares two `uint256` values. Expects first value to be greater than or equal to second.\n function assertGe(uint256 left, uint256 right) external pure;\n\n /// Compares two `uint256` values. Expects first value to be greater than or equal to second.\n /// Includes error message into revert string on failure.\n function assertGe(uint256 left, uint256 right, string calldata error) external pure;\n\n /// Compares two `int256` values. Expects first value to be greater than or equal to second.\n function assertGe(int256 left, int256 right) external pure;\n\n /// Compares two `int256` values. Expects first value to be greater than or equal to second.\n /// Includes error message into revert string on failure.\n function assertGe(int256 left, int256 right, string calldata error) external pure;\n\n /// Compares two `uint256` values. Expects first value to be greater than second.\n /// Formats values with decimals in failure message.\n function assertGtDecimal(uint256 left, uint256 right, uint256 decimals) external pure;\n\n /// Compares two `uint256` values. Expects first value to be greater than second.\n /// Formats values with decimals in failure message. Includes error message into revert string on failure.\n function assertGtDecimal(uint256 left, uint256 right, uint256 decimals, string calldata error) external pure;\n\n /// Compares two `int256` values. Expects first value to be greater than second.\n /// Formats values with decimals in failure message.\n function assertGtDecimal(int256 left, int256 right, uint256 decimals) external pure;\n\n /// Compares two `int256` values. Expects first value to be greater than second.\n /// Formats values with decimals in failure message. Includes error message into revert string on failure.\n function assertGtDecimal(int256 left, int256 right, uint256 decimals, string calldata error) external pure;\n\n /// Compares two `uint256` values. Expects first value to be greater than second.\n function assertGt(uint256 left, uint256 right) external pure;\n\n /// Compares two `uint256` values. Expects first value to be greater than second.\n /// Includes error message into revert string on failure.\n function assertGt(uint256 left, uint256 right, string calldata error) external pure;\n\n /// Compares two `int256` values. Expects first value to be greater than second.\n function assertGt(int256 left, int256 right) external pure;\n\n /// Compares two `int256` values. Expects first value to be greater than second.\n /// Includes error message into revert string on failure.\n function assertGt(int256 left, int256 right, string calldata error) external pure;\n\n /// Compares two `uint256` values. Expects first value to be less than or equal to second.\n /// Formats values with decimals in failure message.\n function assertLeDecimal(uint256 left, uint256 right, uint256 decimals) external pure;\n\n /// Compares two `uint256` values. Expects first value to be less than or equal to second.\n /// Formats values with decimals in failure message. Includes error message into revert string on failure.\n function assertLeDecimal(uint256 left, uint256 right, uint256 decimals, string calldata error) external pure;\n\n /// Compares two `int256` values. Expects first value to be less than or equal to second.\n /// Formats values with decimals in failure message.\n function assertLeDecimal(int256 left, int256 right, uint256 decimals) external pure;\n\n /// Compares two `int256` values. Expects first value to be less than or equal to second.\n /// Formats values with decimals in failure message. Includes error message into revert string on failure.\n function assertLeDecimal(int256 left, int256 right, uint256 decimals, string calldata error) external pure;\n\n /// Compares two `uint256` values. Expects first value to be less than or equal to second.\n function assertLe(uint256 left, uint256 right) external pure;\n\n /// Compares two `uint256` values. Expects first value to be less than or equal to second.\n /// Includes error message into revert string on failure.\n function assertLe(uint256 left, uint256 right, string calldata error) external pure;\n\n /// Compares two `int256` values. Expects first value to be less than or equal to second.\n function assertLe(int256 left, int256 right) external pure;\n\n /// Compares two `int256` values. Expects first value to be less than or equal to second.\n /// Includes error message into revert string on failure.\n function assertLe(int256 left, int256 right, string calldata error) external pure;\n\n /// Compares two `uint256` values. Expects first value to be less than second.\n /// Formats values with decimals in failure message.\n function assertLtDecimal(uint256 left, uint256 right, uint256 decimals) external pure;\n\n /// Compares two `uint256` values. Expects first value to be less than second.\n /// Formats values with decimals in failure message. Includes error message into revert string on failure.\n function assertLtDecimal(uint256 left, uint256 right, uint256 decimals, string calldata error) external pure;\n\n /// Compares two `int256` values. Expects first value to be less than second.\n /// Formats values with decimals in failure message.\n function assertLtDecimal(int256 left, int256 right, uint256 decimals) external pure;\n\n /// Compares two `int256` values. Expects first value to be less than second.\n /// Formats values with decimals in failure message. Includes error message into revert string on failure.\n function assertLtDecimal(int256 left, int256 right, uint256 decimals, string calldata error) external pure;\n\n /// Compares two `uint256` values. Expects first value to be less than second.\n function assertLt(uint256 left, uint256 right) external pure;\n\n /// Compares two `uint256` values. Expects first value to be less than second.\n /// Includes error message into revert string on failure.\n function assertLt(uint256 left, uint256 right, string calldata error) external pure;\n\n /// Compares two `int256` values. Expects first value to be less than second.\n function assertLt(int256 left, int256 right) external pure;\n\n /// Compares two `int256` values. Expects first value to be less than second.\n /// Includes error message into revert string on failure.\n function assertLt(int256 left, int256 right, string calldata error) external pure;\n\n /// Asserts that two `uint256` values are not equal, formatting them with decimals in failure message.\n function assertNotEqDecimal(uint256 left, uint256 right, uint256 decimals) external pure;\n\n /// Asserts that two `uint256` values are not equal, formatting them with decimals in failure message.\n /// Includes error message into revert string on failure.\n function assertNotEqDecimal(uint256 left, uint256 right, uint256 decimals, string calldata error) external pure;\n\n /// Asserts that two `int256` values are not equal, formatting them with decimals in failure message.\n function assertNotEqDecimal(int256 left, int256 right, uint256 decimals) external pure;\n\n /// Asserts that two `int256` values are not equal, formatting them with decimals in failure message.\n /// Includes error message into revert string on failure.\n function assertNotEqDecimal(int256 left, int256 right, uint256 decimals, string calldata error) external pure;\n\n /// Asserts that two `bool` values are not equal.\n function assertNotEq(bool left, bool right) external pure;\n\n /// Asserts that two `bool` values are not equal and includes error message into revert string on failure.\n function assertNotEq(bool left, bool right, string calldata error) external pure;\n\n /// Asserts that two `string` values are not equal.\n function assertNotEq(string calldata left, string calldata right) external pure;\n\n /// Asserts that two `string` values are not equal and includes error message into revert string on failure.\n function assertNotEq(string calldata left, string calldata right, string calldata error) external pure;\n\n /// Asserts that two `bytes` values are not equal.\n function assertNotEq(bytes calldata left, bytes calldata right) external pure;\n\n /// Asserts that two `bytes` values are not equal and includes error message into revert string on failure.\n function assertNotEq(bytes calldata left, bytes calldata right, string calldata error) external pure;\n\n /// Asserts that two arrays of `bool` values are not equal.\n function assertNotEq(bool[] calldata left, bool[] calldata right) external pure;\n\n /// Asserts that two arrays of `bool` values are not equal and includes error message into revert string on failure.\n function assertNotEq(bool[] calldata left, bool[] calldata right, string calldata error) external pure;\n\n /// Asserts that two arrays of `uint256` values are not equal.\n function assertNotEq(uint256[] calldata left, uint256[] calldata right) external pure;\n\n /// Asserts that two arrays of `uint256` values are not equal and includes error message into revert string on failure.\n function assertNotEq(uint256[] calldata left, uint256[] calldata right, string calldata error) external pure;\n\n /// Asserts that two arrays of `int256` values are not equal.\n function assertNotEq(int256[] calldata left, int256[] calldata right) external pure;\n\n /// Asserts that two arrays of `int256` values are not equal and includes error message into revert string on failure.\n function assertNotEq(int256[] calldata left, int256[] calldata right, string calldata error) external pure;\n\n /// Asserts that two `uint256` values are not equal.\n function assertNotEq(uint256 left, uint256 right) external pure;\n\n /// Asserts that two arrays of `address` values are not equal.\n function assertNotEq(address[] calldata left, address[] calldata right) external pure;\n\n /// Asserts that two arrays of `address` values are not equal and includes error message into revert string on failure.\n function assertNotEq(address[] calldata left, address[] calldata right, string calldata error) external pure;\n\n /// Asserts that two arrays of `bytes32` values are not equal.\n function assertNotEq(bytes32[] calldata left, bytes32[] calldata right) external pure;\n\n /// Asserts that two arrays of `bytes32` values are not equal and includes error message into revert string on failure.\n function assertNotEq(bytes32[] calldata left, bytes32[] calldata right, string calldata error) external pure;\n\n /// Asserts that two arrays of `string` values are not equal.\n function assertNotEq(string[] calldata left, string[] calldata right) external pure;\n\n /// Asserts that two arrays of `string` values are not equal and includes error message into revert string on failure.\n function assertNotEq(string[] calldata left, string[] calldata right, string calldata error) external pure;\n\n /// Asserts that two arrays of `bytes` values are not equal.\n function assertNotEq(bytes[] calldata left, bytes[] calldata right) external pure;\n\n /// Asserts that two arrays of `bytes` values are not equal and includes error message into revert string on failure.\n function assertNotEq(bytes[] calldata left, bytes[] calldata right, string calldata error) external pure;\n\n /// Asserts that two `uint256` values are not equal and includes error message into revert string on failure.\n function assertNotEq(uint256 left, uint256 right, string calldata error) external pure;\n\n /// Asserts that two `int256` values are not equal.\n function assertNotEq(int256 left, int256 right) external pure;\n\n /// Asserts that two `int256` values are not equal and includes error message into revert string on failure.\n function assertNotEq(int256 left, int256 right, string calldata error) external pure;\n\n /// Asserts that two `address` values are not equal.\n function assertNotEq(address left, address right) external pure;\n\n /// Asserts that two `address` values are not equal and includes error message into revert string on failure.\n function assertNotEq(address left, address right, string calldata error) external pure;\n\n /// Asserts that two `bytes32` values are not equal.\n function assertNotEq(bytes32 left, bytes32 right) external pure;\n\n /// Asserts that two `bytes32` values are not equal and includes error message into revert string on failure.\n function assertNotEq(bytes32 left, bytes32 right, string calldata error) external pure;\n\n /// Asserts that the given condition is true.\n function assertTrue(bool condition) external pure;\n\n /// Asserts that the given condition is true and includes error message into revert string on failure.\n function assertTrue(bool condition, string calldata error) external pure;\n\n /// If the condition is false, discard this run's fuzz inputs and generate new ones.\n function assume(bool condition) external pure;\n\n /// Discard this run's fuzz inputs and generate new ones if next call reverted.\n function assumeNoRevert() external pure;\n\n /// Writes a breakpoint to jump to in the debugger.\n function breakpoint(string calldata char) external pure;\n\n /// Writes a conditional breakpoint to jump to in the debugger.\n function breakpoint(string calldata char, bool value) external pure;\n\n /// Returns the Foundry version.\n /// Format: ++\n /// Sample output: 0.2.0+faa94c384+202407110019\n /// Note: Build timestamps may vary slightly across platforms due to separate CI jobs.\n /// For reliable version comparisons, use YYYYMMDD0000 format (e.g., >= 202407110000)\n /// to compare timestamps while ignoring minor time differences.\n function getFoundryVersion() external view returns (string memory version);\n\n /// Returns the RPC url for the given alias.\n function rpcUrl(string calldata rpcAlias) external view returns (string memory json);\n\n /// Returns all rpc urls and their aliases as structs.\n function rpcUrlStructs() external view returns (Rpc[] memory urls);\n\n /// Returns all rpc urls and their aliases `[alias, url][]`.\n function rpcUrls() external view returns (string[2][] memory urls);\n\n /// Suspends execution of the main thread for `duration` milliseconds.\n function sleep(uint256 duration) external;\n\n // ======== Toml ========\n\n /// Checks if `key` exists in a TOML table.\n function keyExistsToml(string calldata toml, string calldata key) external view returns (bool);\n\n /// Parses a string of TOML data at `key` and coerces it to `address`.\n function parseTomlAddress(string calldata toml, string calldata key) external pure returns (address);\n\n /// Parses a string of TOML data at `key` and coerces it to `address[]`.\n function parseTomlAddressArray(string calldata toml, string calldata key)\n external\n pure\n returns (address[] memory);\n\n /// Parses a string of TOML data at `key` and coerces it to `bool`.\n function parseTomlBool(string calldata toml, string calldata key) external pure returns (bool);\n\n /// Parses a string of TOML data at `key` and coerces it to `bool[]`.\n function parseTomlBoolArray(string calldata toml, string calldata key) external pure returns (bool[] memory);\n\n /// Parses a string of TOML data at `key` and coerces it to `bytes`.\n function parseTomlBytes(string calldata toml, string calldata key) external pure returns (bytes memory);\n\n /// Parses a string of TOML data at `key` and coerces it to `bytes32`.\n function parseTomlBytes32(string calldata toml, string calldata key) external pure returns (bytes32);\n\n /// Parses a string of TOML data at `key` and coerces it to `bytes32[]`.\n function parseTomlBytes32Array(string calldata toml, string calldata key)\n external\n pure\n returns (bytes32[] memory);\n\n /// Parses a string of TOML data at `key` and coerces it to `bytes[]`.\n function parseTomlBytesArray(string calldata toml, string calldata key) external pure returns (bytes[] memory);\n\n /// Parses a string of TOML data at `key` and coerces it to `int256`.\n function parseTomlInt(string calldata toml, string calldata key) external pure returns (int256);\n\n /// Parses a string of TOML data at `key` and coerces it to `int256[]`.\n function parseTomlIntArray(string calldata toml, string calldata key) external pure returns (int256[] memory);\n\n /// Returns an array of all the keys in a TOML table.\n function parseTomlKeys(string calldata toml, string calldata key) external pure returns (string[] memory keys);\n\n /// Parses a string of TOML data at `key` and coerces it to `string`.\n function parseTomlString(string calldata toml, string calldata key) external pure returns (string memory);\n\n /// Parses a string of TOML data at `key` and coerces it to `string[]`.\n function parseTomlStringArray(string calldata toml, string calldata key) external pure returns (string[] memory);\n\n /// Parses a string of TOML data at `key` and coerces it to type array corresponding to `typeDescription`.\n function parseTomlTypeArray(string calldata toml, string calldata key, string calldata typeDescription)\n external\n pure\n returns (bytes memory);\n\n /// Parses a string of TOML data and coerces it to type corresponding to `typeDescription`.\n function parseTomlType(string calldata toml, string calldata typeDescription)\n external\n pure\n returns (bytes memory);\n\n /// Parses a string of TOML data at `key` and coerces it to type corresponding to `typeDescription`.\n function parseTomlType(string calldata toml, string calldata key, string calldata typeDescription)\n external\n pure\n returns (bytes memory);\n\n /// Parses a string of TOML data at `key` and coerces it to `uint256`.\n function parseTomlUint(string calldata toml, string calldata key) external pure returns (uint256);\n\n /// Parses a string of TOML data at `key` and coerces it to `uint256[]`.\n function parseTomlUintArray(string calldata toml, string calldata key) external pure returns (uint256[] memory);\n\n /// ABI-encodes a TOML table.\n function parseToml(string calldata toml) external pure returns (bytes memory abiEncodedData);\n\n /// ABI-encodes a TOML table at `key`.\n function parseToml(string calldata toml, string calldata key) external pure returns (bytes memory abiEncodedData);\n\n /// Takes serialized JSON, converts to TOML and write a serialized TOML to a file.\n function writeToml(string calldata json, string calldata path) external;\n\n /// Takes serialized JSON, converts to TOML and write a serialized TOML table to an **existing** TOML file, replacing a value with key = \n /// This is useful to replace a specific value of a TOML file, without having to parse the entire thing.\n function writeToml(string calldata json, string calldata path, string calldata valueKey) external;\n\n // ======== Utilities ========\n\n /// Compute the address of a contract created with CREATE2 using the given CREATE2 deployer.\n function computeCreate2Address(bytes32 salt, bytes32 initCodeHash, address deployer)\n external\n pure\n returns (address);\n\n /// Compute the address of a contract created with CREATE2 using the default CREATE2 deployer.\n function computeCreate2Address(bytes32 salt, bytes32 initCodeHash) external pure returns (address);\n\n /// Compute the address a contract will be deployed at for a given deployer address and nonce.\n function computeCreateAddress(address deployer, uint256 nonce) external pure returns (address);\n\n /// Utility cheatcode to copy storage of `from` contract to another `to` contract.\n function copyStorage(address from, address to) external;\n\n /// Returns ENS namehash for provided string.\n function ensNamehash(string calldata name) external pure returns (bytes32);\n\n /// Gets the label for the specified address.\n function getLabel(address account) external view returns (string memory currentLabel);\n\n /// Labels an address in call traces.\n function label(address account, string calldata newLabel) external;\n\n /// Pauses collection of call traces. Useful in cases when you want to skip tracing of\n /// complex calls which are not useful for debugging.\n function pauseTracing() external view;\n\n /// Returns a random `address`.\n function randomAddress() external returns (address);\n\n /// Returns a random `bool`.\n function randomBool() external view returns (bool);\n\n /// Returns a random byte array value of the given length.\n function randomBytes(uint256 len) external view returns (bytes memory);\n\n /// Returns a random fixed-size byte array of length 4.\n function randomBytes4() external view returns (bytes4);\n\n /// Returns a random fixed-size byte array of length 8.\n function randomBytes8() external view returns (bytes8);\n\n /// Returns a random `int256` value.\n function randomInt() external view returns (int256);\n\n /// Returns a random `int256` value of given bits.\n function randomInt(uint256 bits) external view returns (int256);\n\n /// Returns a random uint256 value.\n function randomUint() external returns (uint256);\n\n /// Returns random uint256 value between the provided range (=min..=max).\n function randomUint(uint256 min, uint256 max) external returns (uint256);\n\n /// Returns a random `uint256` value of given bits.\n function randomUint(uint256 bits) external view returns (uint256);\n\n /// Unpauses collection of call traces.\n function resumeTracing() external view;\n\n /// Utility cheatcode to set arbitrary storage for given target address.\n function setArbitraryStorage(address target) external;\n\n /// Encodes a `bytes` value to a base64url string.\n function toBase64URL(bytes calldata data) external pure returns (string memory);\n\n /// Encodes a `string` value to a base64url string.\n function toBase64URL(string calldata data) external pure returns (string memory);\n\n /// Encodes a `bytes` value to a base64 string.\n function toBase64(bytes calldata data) external pure returns (string memory);\n\n /// Encodes a `string` value to a base64 string.\n function toBase64(string calldata data) external pure returns (string memory);\n}\n\n/// The `Vm` interface does allow manipulation of the EVM state. These are all intended to be used\n/// in tests, but it is not recommended to use these cheats in scripts.\ninterface Vm is VmSafe {\n // ======== EVM ========\n\n /// Returns the identifier of the currently active fork. Reverts if no fork is currently active.\n function activeFork() external view returns (uint256 forkId);\n\n /// In forking mode, explicitly grant the given address cheatcode access.\n function allowCheatcodes(address account) external;\n\n /// Sets `block.blobbasefee`\n function blobBaseFee(uint256 newBlobBaseFee) external;\n\n /// Sets the blobhashes in the transaction.\n /// Not available on EVM versions before Cancun.\n /// If used on unsupported EVM versions it will revert.\n function blobhashes(bytes32[] calldata hashes) external;\n\n /// Sets `block.chainid`.\n function chainId(uint256 newChainId) external;\n\n /// Clears all mocked calls.\n function clearMockedCalls() external;\n\n /// Clones a source account code, state, balance and nonce to a target account and updates in-memory EVM state.\n function cloneAccount(address source, address target) external;\n\n /// Sets `block.coinbase`.\n function coinbase(address newCoinbase) external;\n\n /// Creates a new fork with the given endpoint and the _latest_ block and returns the identifier of the fork.\n function createFork(string calldata urlOrAlias) external returns (uint256 forkId);\n\n /// Creates a new fork with the given endpoint and block and returns the identifier of the fork.\n function createFork(string calldata urlOrAlias, uint256 blockNumber) external returns (uint256 forkId);\n\n /// Creates a new fork with the given endpoint and at the block the given transaction was mined in,\n /// replays all transaction mined in the block before the transaction, and returns the identifier of the fork.\n function createFork(string calldata urlOrAlias, bytes32 txHash) external returns (uint256 forkId);\n\n /// Creates and also selects a new fork with the given endpoint and the latest block and returns the identifier of the fork.\n function createSelectFork(string calldata urlOrAlias) external returns (uint256 forkId);\n\n /// Creates and also selects a new fork with the given endpoint and block and returns the identifier of the fork.\n function createSelectFork(string calldata urlOrAlias, uint256 blockNumber) external returns (uint256 forkId);\n\n /// Creates and also selects new fork with the given endpoint and at the block the given transaction was mined in,\n /// replays all transaction mined in the block before the transaction, returns the identifier of the fork.\n function createSelectFork(string calldata urlOrAlias, bytes32 txHash) external returns (uint256 forkId);\n\n /// Sets an address' balance.\n function deal(address account, uint256 newBalance) external;\n\n /// Removes the snapshot with the given ID created by `snapshot`.\n /// Takes the snapshot ID to delete.\n /// Returns `true` if the snapshot was successfully deleted.\n /// Returns `false` if the snapshot does not exist.\n function deleteStateSnapshot(uint256 snapshotId) external returns (bool success);\n\n /// Removes _all_ snapshots previously created by `snapshot`.\n function deleteStateSnapshots() external;\n\n /// Sets `block.difficulty`.\n /// Not available on EVM versions from Paris onwards. Use `prevrandao` instead.\n /// Reverts if used on unsupported EVM versions.\n function difficulty(uint256 newDifficulty) external;\n\n /// Dump a genesis JSON file's `allocs` to disk.\n function dumpState(string calldata pathToStateJson) external;\n\n /// Sets an address' code.\n function etch(address target, bytes calldata newRuntimeBytecode) external;\n\n /// Sets `block.basefee`.\n function fee(uint256 newBasefee) external;\n\n /// Gets the blockhashes from the current transaction.\n /// Not available on EVM versions before Cancun.\n /// If used on unsupported EVM versions it will revert.\n function getBlobhashes() external view returns (bytes32[] memory hashes);\n\n /// Returns true if the account is marked as persistent.\n function isPersistent(address account) external view returns (bool persistent);\n\n /// Load a genesis JSON file's `allocs` into the in-memory EVM state.\n function loadAllocs(string calldata pathToAllocsJson) external;\n\n /// Marks that the account(s) should use persistent storage across fork swaps in a multifork setup\n /// Meaning, changes made to the state of this account will be kept when switching forks.\n function makePersistent(address account) external;\n\n /// See `makePersistent(address)`.\n function makePersistent(address account0, address account1) external;\n\n /// See `makePersistent(address)`.\n function makePersistent(address account0, address account1, address account2) external;\n\n /// See `makePersistent(address)`.\n function makePersistent(address[] calldata accounts) external;\n\n /// Reverts a call to an address with specified revert data.\n function mockCallRevert(address callee, bytes calldata data, bytes calldata revertData) external;\n\n /// Reverts a call to an address with a specific `msg.value`, with specified revert data.\n function mockCallRevert(address callee, uint256 msgValue, bytes calldata data, bytes calldata revertData)\n external;\n\n /// Reverts a call to an address with specified revert data.\n /// Overload to pass the function selector directly `token.approve.selector` instead of `abi.encodeWithSelector(token.approve.selector)`.\n function mockCallRevert(address callee, bytes4 data, bytes calldata revertData) external;\n\n /// Reverts a call to an address with a specific `msg.value`, with specified revert data.\n /// Overload to pass the function selector directly `token.approve.selector` instead of `abi.encodeWithSelector(token.approve.selector)`.\n function mockCallRevert(address callee, uint256 msgValue, bytes4 data, bytes calldata revertData) external;\n\n /// Mocks a call to an address, returning specified data.\n /// Calldata can either be strict or a partial match, e.g. if you only\n /// pass a Solidity selector to the expected calldata, then the entire Solidity\n /// function will be mocked.\n function mockCall(address callee, bytes calldata data, bytes calldata returnData) external;\n\n /// Mocks a call to an address with a specific `msg.value`, returning specified data.\n /// Calldata match takes precedence over `msg.value` in case of ambiguity.\n function mockCall(address callee, uint256 msgValue, bytes calldata data, bytes calldata returnData) external;\n\n /// Mocks a call to an address, returning specified data.\n /// Calldata can either be strict or a partial match, e.g. if you only\n /// pass a Solidity selector to the expected calldata, then the entire Solidity\n /// function will be mocked.\n /// Overload to pass the function selector directly `token.approve.selector` instead of `abi.encodeWithSelector(token.approve.selector)`.\n function mockCall(address callee, bytes4 data, bytes calldata returnData) external;\n\n /// Mocks a call to an address with a specific `msg.value`, returning specified data.\n /// Calldata match takes precedence over `msg.value` in case of ambiguity.\n /// Overload to pass the function selector directly `token.approve.selector` instead of `abi.encodeWithSelector(token.approve.selector)`.\n function mockCall(address callee, uint256 msgValue, bytes4 data, bytes calldata returnData) external;\n\n /// Mocks multiple calls to an address, returning specified data for each call.\n function mockCalls(address callee, bytes calldata data, bytes[] calldata returnData) external;\n\n /// Mocks multiple calls to an address with a specific `msg.value`, returning specified data for each call.\n function mockCalls(address callee, uint256 msgValue, bytes calldata data, bytes[] calldata returnData) external;\n\n /// Whenever a call is made to `callee` with calldata `data`, this cheatcode instead calls\n /// `target` with the same calldata. This functionality is similar to a delegate call made to\n /// `target` contract from `callee`.\n /// Can be used to substitute a call to a function with another implementation that captures\n /// the primary logic of the original function but is easier to reason about.\n /// If calldata is not a strict match then partial match by selector is attempted.\n function mockFunction(address callee, address target, bytes calldata data) external;\n\n /// Sets the *next* call's `msg.sender` to be the input address.\n function prank(address msgSender) external;\n\n /// Sets the *next* call's `msg.sender` to be the input address, and the `tx.origin` to be the second input.\n function prank(address msgSender, address txOrigin) external;\n\n /// Sets the *next* delegate call's `msg.sender` to be the input address.\n function prank(address msgSender, bool delegateCall) external;\n\n /// Sets the *next* delegate call's `msg.sender` to be the input address, and the `tx.origin` to be the second input.\n function prank(address msgSender, address txOrigin, bool delegateCall) external;\n\n /// Sets `block.prevrandao`.\n /// Not available on EVM versions before Paris. Use `difficulty` instead.\n /// If used on unsupported EVM versions it will revert.\n function prevrandao(bytes32 newPrevrandao) external;\n\n /// Sets `block.prevrandao`.\n /// Not available on EVM versions before Paris. Use `difficulty` instead.\n /// If used on unsupported EVM versions it will revert.\n function prevrandao(uint256 newPrevrandao) external;\n\n /// Reads the current `msg.sender` and `tx.origin` from state and reports if there is any active caller modification.\n function readCallers() external returns (CallerMode callerMode, address msgSender, address txOrigin);\n\n /// Resets the nonce of an account to 0 for EOAs and 1 for contract accounts.\n function resetNonce(address account) external;\n\n /// Revert the state of the EVM to a previous snapshot\n /// Takes the snapshot ID to revert to.\n /// Returns `true` if the snapshot was successfully reverted.\n /// Returns `false` if the snapshot does not exist.\n /// **Note:** This does not automatically delete the snapshot. To delete the snapshot use `deleteStateSnapshot`.\n function revertToState(uint256 snapshotId) external returns (bool success);\n\n /// Revert the state of the EVM to a previous snapshot and automatically deletes the snapshots\n /// Takes the snapshot ID to revert to.\n /// Returns `true` if the snapshot was successfully reverted and deleted.\n /// Returns `false` if the snapshot does not exist.\n function revertToStateAndDelete(uint256 snapshotId) external returns (bool success);\n\n /// Revokes persistent status from the address, previously added via `makePersistent`.\n function revokePersistent(address account) external;\n\n /// See `revokePersistent(address)`.\n function revokePersistent(address[] calldata accounts) external;\n\n /// Sets `block.height`.\n function roll(uint256 newHeight) external;\n\n /// Updates the currently active fork to given block number\n /// This is similar to `roll` but for the currently active fork.\n function rollFork(uint256 blockNumber) external;\n\n /// Updates the currently active fork to given transaction. This will `rollFork` with the number\n /// of the block the transaction was mined in and replays all transaction mined before it in the block.\n function rollFork(bytes32 txHash) external;\n\n /// Updates the given fork to given block number.\n function rollFork(uint256 forkId, uint256 blockNumber) external;\n\n /// Updates the given fork to block number of the given transaction and replays all transaction mined before it in the block.\n function rollFork(uint256 forkId, bytes32 txHash) external;\n\n /// Takes a fork identifier created by `createFork` and sets the corresponding forked state as active.\n function selectFork(uint256 forkId) external;\n\n /// Set blockhash for the current block.\n /// It only sets the blockhash for blocks where `block.number - 256 <= number < block.number`.\n function setBlockhash(uint256 blockNumber, bytes32 blockHash) external;\n\n /// Sets the nonce of an account. Must be higher than the current nonce of the account.\n function setNonce(address account, uint64 newNonce) external;\n\n /// Sets the nonce of an account to an arbitrary value.\n function setNonceUnsafe(address account, uint64 newNonce) external;\n\n /// Snapshot capture the gas usage of the last call by name from the callee perspective.\n function snapshotGasLastCall(string calldata name) external returns (uint256 gasUsed);\n\n /// Snapshot capture the gas usage of the last call by name in a group from the callee perspective.\n function snapshotGasLastCall(string calldata group, string calldata name) external returns (uint256 gasUsed);\n\n /// Snapshot the current state of the evm.\n /// Returns the ID of the snapshot that was created.\n /// To revert a snapshot use `revertToState`.\n function snapshotState() external returns (uint256 snapshotId);\n\n /// Snapshot capture an arbitrary numerical value by name.\n /// The group name is derived from the contract name.\n function snapshotValue(string calldata name, uint256 value) external;\n\n /// Snapshot capture an arbitrary numerical value by name in a group.\n function snapshotValue(string calldata group, string calldata name, uint256 value) external;\n\n /// Sets all subsequent calls' `msg.sender` to be the input address until `stopPrank` is called.\n function startPrank(address msgSender) external;\n\n /// Sets all subsequent calls' `msg.sender` to be the input address until `stopPrank` is called, and the `tx.origin` to be the second input.\n function startPrank(address msgSender, address txOrigin) external;\n\n /// Sets all subsequent delegate calls' `msg.sender` to be the input address until `stopPrank` is called.\n function startPrank(address msgSender, bool delegateCall) external;\n\n /// Sets all subsequent delegate calls' `msg.sender` to be the input address until `stopPrank` is called, and the `tx.origin` to be the second input.\n function startPrank(address msgSender, address txOrigin, bool delegateCall) external;\n\n /// Start a snapshot capture of the current gas usage by name.\n /// The group name is derived from the contract name.\n function startSnapshotGas(string calldata name) external;\n\n /// Start a snapshot capture of the current gas usage by name in a group.\n function startSnapshotGas(string calldata group, string calldata name) external;\n\n /// Resets subsequent calls' `msg.sender` to be `address(this)`.\n function stopPrank() external;\n\n /// Stop the snapshot capture of the current gas by latest snapshot name, capturing the gas used since the start.\n function stopSnapshotGas() external returns (uint256 gasUsed);\n\n /// Stop the snapshot capture of the current gas usage by name, capturing the gas used since the start.\n /// The group name is derived from the contract name.\n function stopSnapshotGas(string calldata name) external returns (uint256 gasUsed);\n\n /// Stop the snapshot capture of the current gas usage by name in a group, capturing the gas used since the start.\n function stopSnapshotGas(string calldata group, string calldata name) external returns (uint256 gasUsed);\n\n /// Stores a value to an address' storage slot.\n function store(address target, bytes32 slot, bytes32 value) external;\n\n /// Fetches the given transaction from the active fork and executes it on the current state.\n function transact(bytes32 txHash) external;\n\n /// Fetches the given transaction from the given fork and executes it on the current state.\n function transact(uint256 forkId, bytes32 txHash) external;\n\n /// Sets `tx.gasprice`.\n function txGasPrice(uint256 newGasPrice) external;\n\n /// Sets `block.timestamp`.\n function warp(uint256 newTimestamp) external;\n\n /// `deleteSnapshot` is being deprecated in favor of `deleteStateSnapshot`. It will be removed in future versions.\n function deleteSnapshot(uint256 snapshotId) external returns (bool success);\n\n /// `deleteSnapshots` is being deprecated in favor of `deleteStateSnapshots`. It will be removed in future versions.\n function deleteSnapshots() external;\n\n /// `revertToAndDelete` is being deprecated in favor of `revertToStateAndDelete`. It will be removed in future versions.\n function revertToAndDelete(uint256 snapshotId) external returns (bool success);\n\n /// `revertTo` is being deprecated in favor of `revertToState`. It will be removed in future versions.\n function revertTo(uint256 snapshotId) external returns (bool success);\n\n /// `snapshot` is being deprecated in favor of `snapshotState`. It will be removed in future versions.\n function snapshot() external returns (uint256 snapshotId);\n\n // ======== Testing ========\n\n /// Expect a call to an address with the specified `msg.value` and calldata, and a *minimum* amount of gas.\n function expectCallMinGas(address callee, uint256 msgValue, uint64 minGas, bytes calldata data) external;\n\n /// Expect given number of calls to an address with the specified `msg.value` and calldata, and a *minimum* amount of gas.\n function expectCallMinGas(address callee, uint256 msgValue, uint64 minGas, bytes calldata data, uint64 count)\n external;\n\n /// Expects a call to an address with the specified calldata.\n /// Calldata can either be a strict or a partial match.\n function expectCall(address callee, bytes calldata data) external;\n\n /// Expects given number of calls to an address with the specified calldata.\n function expectCall(address callee, bytes calldata data, uint64 count) external;\n\n /// Expects a call to an address with the specified `msg.value` and calldata.\n function expectCall(address callee, uint256 msgValue, bytes calldata data) external;\n\n /// Expects given number of calls to an address with the specified `msg.value` and calldata.\n function expectCall(address callee, uint256 msgValue, bytes calldata data, uint64 count) external;\n\n /// Expect a call to an address with the specified `msg.value`, gas, and calldata.\n function expectCall(address callee, uint256 msgValue, uint64 gas, bytes calldata data) external;\n\n /// Expects given number of calls to an address with the specified `msg.value`, gas, and calldata.\n function expectCall(address callee, uint256 msgValue, uint64 gas, bytes calldata data, uint64 count) external;\n\n /// Prepare an expected anonymous log with (bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData.).\n /// Call this function, then emit an anonymous event, then call a function. Internally after the call, we check if\n /// logs were emitted in the expected order with the expected topics and data (as specified by the booleans).\n function expectEmitAnonymous(bool checkTopic0, bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData)\n external;\n\n /// Same as the previous method, but also checks supplied address against emitting contract.\n function expectEmitAnonymous(\n bool checkTopic0,\n bool checkTopic1,\n bool checkTopic2,\n bool checkTopic3,\n bool checkData,\n address emitter\n ) external;\n\n /// Prepare an expected anonymous log with all topic and data checks enabled.\n /// Call this function, then emit an anonymous event, then call a function. Internally after the call, we check if\n /// logs were emitted in the expected order with the expected topics and data.\n function expectEmitAnonymous() external;\n\n /// Same as the previous method, but also checks supplied address against emitting contract.\n function expectEmitAnonymous(address emitter) external;\n\n /// Prepare an expected log with (bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData.).\n /// Call this function, then emit an event, then call a function. Internally after the call, we check if\n /// logs were emitted in the expected order with the expected topics and data (as specified by the booleans).\n function expectEmit(bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData) external;\n\n /// Same as the previous method, but also checks supplied address against emitting contract.\n function expectEmit(bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData, address emitter)\n external;\n\n /// Prepare an expected log with all topic and data checks enabled.\n /// Call this function, then emit an event, then call a function. Internally after the call, we check if\n /// logs were emitted in the expected order with the expected topics and data.\n function expectEmit() external;\n\n /// Same as the previous method, but also checks supplied address against emitting contract.\n function expectEmit(address emitter) external;\n\n /// Expect a given number of logs with the provided topics.\n function expectEmit(bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData, uint64 count) external;\n\n /// Expect a given number of logs from a specific emitter with the provided topics.\n function expectEmit(\n bool checkTopic1,\n bool checkTopic2,\n bool checkTopic3,\n bool checkData,\n address emitter,\n uint64 count\n ) external;\n\n /// Expect a given number of logs with all topic and data checks enabled.\n function expectEmit(uint64 count) external;\n\n /// Expect a given number of logs from a specific emitter with all topic and data checks enabled.\n function expectEmit(address emitter, uint64 count) external;\n\n /// Expects an error on next call that starts with the revert data.\n function expectPartialRevert(bytes4 revertData) external;\n\n /// Expects an error on next call to reverter address, that starts with the revert data.\n function expectPartialRevert(bytes4 revertData, address reverter) external;\n\n /// Expects an error on next call with any revert data.\n function expectRevert() external;\n\n /// Expects an error on next call that exactly matches the revert data.\n function expectRevert(bytes4 revertData) external;\n\n /// Expects a `count` number of reverts from the upcoming calls from the reverter address that match the revert data.\n function expectRevert(bytes4 revertData, address reverter, uint64 count) external;\n\n /// Expects a `count` number of reverts from the upcoming calls from the reverter address that exactly match the revert data.\n function expectRevert(bytes calldata revertData, address reverter, uint64 count) external;\n\n /// Expects an error on next call that exactly matches the revert data.\n function expectRevert(bytes calldata revertData) external;\n\n /// Expects an error with any revert data on next call to reverter address.\n function expectRevert(address reverter) external;\n\n /// Expects an error from reverter address on next call, with any revert data.\n function expectRevert(bytes4 revertData, address reverter) external;\n\n /// Expects an error from reverter address on next call, that exactly matches the revert data.\n function expectRevert(bytes calldata revertData, address reverter) external;\n\n /// Expects a `count` number of reverts from the upcoming calls with any revert data or reverter.\n function expectRevert(uint64 count) external;\n\n /// Expects a `count` number of reverts from the upcoming calls that match the revert data.\n function expectRevert(bytes4 revertData, uint64 count) external;\n\n /// Expects a `count` number of reverts from the upcoming calls that exactly match the revert data.\n function expectRevert(bytes calldata revertData, uint64 count) external;\n\n /// Expects a `count` number of reverts from the upcoming calls from the reverter address.\n function expectRevert(address reverter, uint64 count) external;\n\n /// Only allows memory writes to offsets [0x00, 0x60) ∪ [min, max) in the current subcontext. If any other\n /// memory is written to, the test will fail. Can be called multiple times to add more ranges to the set.\n function expectSafeMemory(uint64 min, uint64 max) external;\n\n /// Only allows memory writes to offsets [0x00, 0x60) ∪ [min, max) in the next created subcontext.\n /// If any other memory is written to, the test will fail. Can be called multiple times to add more ranges\n /// to the set.\n function expectSafeMemoryCall(uint64 min, uint64 max) external;\n\n /// Marks a test as skipped. Must be called at the top level of a test.\n function skip(bool skipTest) external;\n\n /// Marks a test as skipped with a reason. Must be called at the top level of a test.\n function skip(bool skipTest, string calldata reason) external;\n\n /// Stops all safe memory expectation in the current subcontext.\n function stopExpectSafeMemory() external;\n}\n" + }, + "lib/forge-std/src/console.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.4.22 <0.9.0;\n\nlibrary console {\n address constant CONSOLE_ADDRESS =\n 0x000000000000000000636F6e736F6c652e6c6f67;\n\n function _sendLogPayloadImplementation(bytes memory payload) internal view {\n address consoleAddress = CONSOLE_ADDRESS;\n /// @solidity memory-safe-assembly\n assembly {\n pop(\n staticcall(\n gas(),\n consoleAddress,\n add(payload, 32),\n mload(payload),\n 0,\n 0\n )\n )\n }\n }\n\n function _castToPure(\n function(bytes memory) internal view fnIn\n ) internal pure returns (function(bytes memory) pure fnOut) {\n assembly {\n fnOut := fnIn\n }\n }\n\n function _sendLogPayload(bytes memory payload) internal pure {\n _castToPure(_sendLogPayloadImplementation)(payload);\n }\n\n function log() internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log()\"));\n }\n\n function logInt(int256 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(int256)\", p0));\n }\n\n function logUint(uint256 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256)\", p0));\n }\n\n function logString(string memory p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string)\", p0));\n }\n\n function logBool(bool p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool)\", p0));\n }\n\n function logAddress(address p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address)\", p0));\n }\n\n function logBytes(bytes memory p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes)\", p0));\n }\n\n function logBytes1(bytes1 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes1)\", p0));\n }\n\n function logBytes2(bytes2 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes2)\", p0));\n }\n\n function logBytes3(bytes3 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes3)\", p0));\n }\n\n function logBytes4(bytes4 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes4)\", p0));\n }\n\n function logBytes5(bytes5 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes5)\", p0));\n }\n\n function logBytes6(bytes6 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes6)\", p0));\n }\n\n function logBytes7(bytes7 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes7)\", p0));\n }\n\n function logBytes8(bytes8 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes8)\", p0));\n }\n\n function logBytes9(bytes9 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes9)\", p0));\n }\n\n function logBytes10(bytes10 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes10)\", p0));\n }\n\n function logBytes11(bytes11 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes11)\", p0));\n }\n\n function logBytes12(bytes12 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes12)\", p0));\n }\n\n function logBytes13(bytes13 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes13)\", p0));\n }\n\n function logBytes14(bytes14 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes14)\", p0));\n }\n\n function logBytes15(bytes15 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes15)\", p0));\n }\n\n function logBytes16(bytes16 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes16)\", p0));\n }\n\n function logBytes17(bytes17 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes17)\", p0));\n }\n\n function logBytes18(bytes18 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes18)\", p0));\n }\n\n function logBytes19(bytes19 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes19)\", p0));\n }\n\n function logBytes20(bytes20 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes20)\", p0));\n }\n\n function logBytes21(bytes21 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes21)\", p0));\n }\n\n function logBytes22(bytes22 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes22)\", p0));\n }\n\n function logBytes23(bytes23 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes23)\", p0));\n }\n\n function logBytes24(bytes24 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes24)\", p0));\n }\n\n function logBytes25(bytes25 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes25)\", p0));\n }\n\n function logBytes26(bytes26 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes26)\", p0));\n }\n\n function logBytes27(bytes27 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes27)\", p0));\n }\n\n function logBytes28(bytes28 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes28)\", p0));\n }\n\n function logBytes29(bytes29 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes29)\", p0));\n }\n\n function logBytes30(bytes30 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes30)\", p0));\n }\n\n function logBytes31(bytes31 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes31)\", p0));\n }\n\n function logBytes32(bytes32 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bytes32)\", p0));\n }\n\n function log(uint256 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256)\", p0));\n }\n\n function log(int256 p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(int256)\", p0));\n }\n\n function log(string memory p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string)\", p0));\n }\n\n function log(bool p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool)\", p0));\n }\n\n function log(address p0) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address)\", p0));\n }\n\n function log(uint256 p0, uint256 p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256)\", p0, p1));\n }\n\n function log(uint256 p0, string memory p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string)\", p0, p1));\n }\n\n function log(uint256 p0, bool p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool)\", p0, p1));\n }\n\n function log(uint256 p0, address p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address)\", p0, p1));\n }\n\n function log(string memory p0, uint256 p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256)\", p0, p1));\n }\n\n function log(string memory p0, int256 p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,int256)\", p0, p1));\n }\n\n function log(string memory p0, string memory p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string)\", p0, p1));\n }\n\n function log(string memory p0, bool p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool)\", p0, p1));\n }\n\n function log(string memory p0, address p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address)\", p0, p1));\n }\n\n function log(bool p0, uint256 p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256)\", p0, p1));\n }\n\n function log(bool p0, string memory p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string)\", p0, p1));\n }\n\n function log(bool p0, bool p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool)\", p0, p1));\n }\n\n function log(bool p0, address p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address)\", p0, p1));\n }\n\n function log(address p0, uint256 p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256)\", p0, p1));\n }\n\n function log(address p0, string memory p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string)\", p0, p1));\n }\n\n function log(address p0, bool p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool)\", p0, p1));\n }\n\n function log(address p0, address p1) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address)\", p0, p1));\n }\n\n function log(uint256 p0, uint256 p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,uint256)\", p0, p1, p2));\n }\n\n function log(uint256 p0, uint256 p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,string)\", p0, p1, p2));\n }\n\n function log(uint256 p0, uint256 p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,bool)\", p0, p1, p2));\n }\n\n function log(uint256 p0, uint256 p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,address)\", p0, p1, p2));\n }\n\n function log(uint256 p0, string memory p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,uint256)\", p0, p1, p2));\n }\n\n function log(uint256 p0, string memory p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,string)\", p0, p1, p2));\n }\n\n function log(uint256 p0, string memory p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,bool)\", p0, p1, p2));\n }\n\n function log(uint256 p0, string memory p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,address)\", p0, p1, p2));\n }\n\n function log(uint256 p0, bool p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,uint256)\", p0, p1, p2));\n }\n\n function log(uint256 p0, bool p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,string)\", p0, p1, p2));\n }\n\n function log(uint256 p0, bool p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,bool)\", p0, p1, p2));\n }\n\n function log(uint256 p0, bool p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,address)\", p0, p1, p2));\n }\n\n function log(uint256 p0, address p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,uint256)\", p0, p1, p2));\n }\n\n function log(uint256 p0, address p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,string)\", p0, p1, p2));\n }\n\n function log(uint256 p0, address p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,bool)\", p0, p1, p2));\n }\n\n function log(uint256 p0, address p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,address)\", p0, p1, p2));\n }\n\n function log(string memory p0, uint256 p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,uint256)\", p0, p1, p2));\n }\n\n function log(string memory p0, uint256 p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,string)\", p0, p1, p2));\n }\n\n function log(string memory p0, uint256 p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,bool)\", p0, p1, p2));\n }\n\n function log(string memory p0, uint256 p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,address)\", p0, p1, p2));\n }\n\n function log(string memory p0, string memory p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,uint256)\", p0, p1, p2));\n }\n\n function log(string memory p0, string memory p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,string)\", p0, p1, p2));\n }\n\n function log(string memory p0, string memory p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,bool)\", p0, p1, p2));\n }\n\n function log(string memory p0, string memory p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,address)\", p0, p1, p2));\n }\n\n function log(string memory p0, bool p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,uint256)\", p0, p1, p2));\n }\n\n function log(string memory p0, bool p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,string)\", p0, p1, p2));\n }\n\n function log(string memory p0, bool p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,bool)\", p0, p1, p2));\n }\n\n function log(string memory p0, bool p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,address)\", p0, p1, p2));\n }\n\n function log(string memory p0, address p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,uint256)\", p0, p1, p2));\n }\n\n function log(string memory p0, address p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,string)\", p0, p1, p2));\n }\n\n function log(string memory p0, address p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,bool)\", p0, p1, p2));\n }\n\n function log(string memory p0, address p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,address)\", p0, p1, p2));\n }\n\n function log(bool p0, uint256 p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,uint256)\", p0, p1, p2));\n }\n\n function log(bool p0, uint256 p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,string)\", p0, p1, p2));\n }\n\n function log(bool p0, uint256 p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,bool)\", p0, p1, p2));\n }\n\n function log(bool p0, uint256 p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,address)\", p0, p1, p2));\n }\n\n function log(bool p0, string memory p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,uint256)\", p0, p1, p2));\n }\n\n function log(bool p0, string memory p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,string)\", p0, p1, p2));\n }\n\n function log(bool p0, string memory p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,bool)\", p0, p1, p2));\n }\n\n function log(bool p0, string memory p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,address)\", p0, p1, p2));\n }\n\n function log(bool p0, bool p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,uint256)\", p0, p1, p2));\n }\n\n function log(bool p0, bool p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,string)\", p0, p1, p2));\n }\n\n function log(bool p0, bool p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,bool)\", p0, p1, p2));\n }\n\n function log(bool p0, bool p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,address)\", p0, p1, p2));\n }\n\n function log(bool p0, address p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,uint256)\", p0, p1, p2));\n }\n\n function log(bool p0, address p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,string)\", p0, p1, p2));\n }\n\n function log(bool p0, address p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,bool)\", p0, p1, p2));\n }\n\n function log(bool p0, address p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,address)\", p0, p1, p2));\n }\n\n function log(address p0, uint256 p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,uint256)\", p0, p1, p2));\n }\n\n function log(address p0, uint256 p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,string)\", p0, p1, p2));\n }\n\n function log(address p0, uint256 p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,bool)\", p0, p1, p2));\n }\n\n function log(address p0, uint256 p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,address)\", p0, p1, p2));\n }\n\n function log(address p0, string memory p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,uint256)\", p0, p1, p2));\n }\n\n function log(address p0, string memory p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,string)\", p0, p1, p2));\n }\n\n function log(address p0, string memory p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,bool)\", p0, p1, p2));\n }\n\n function log(address p0, string memory p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,address)\", p0, p1, p2));\n }\n\n function log(address p0, bool p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,uint256)\", p0, p1, p2));\n }\n\n function log(address p0, bool p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,string)\", p0, p1, p2));\n }\n\n function log(address p0, bool p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,bool)\", p0, p1, p2));\n }\n\n function log(address p0, bool p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,address)\", p0, p1, p2));\n }\n\n function log(address p0, address p1, uint256 p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,uint256)\", p0, p1, p2));\n }\n\n function log(address p0, address p1, string memory p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,string)\", p0, p1, p2));\n }\n\n function log(address p0, address p1, bool p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,bool)\", p0, p1, p2));\n }\n\n function log(address p0, address p1, address p2) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,address)\", p0, p1, p2));\n }\n\n function log(uint256 p0, uint256 p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, uint256 p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, uint256 p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, uint256 p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, uint256 p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, uint256 p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,string,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, uint256 p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, uint256 p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,string,address)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, uint256 p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, uint256 p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, uint256 p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, uint256 p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, uint256 p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, uint256 p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,address,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, uint256 p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, uint256 p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,address,address)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,string,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,string,address)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,address,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, string memory p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,address,address)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,string,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,string,address)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,address,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, bool p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,address,address)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,string,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,string,address)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,address,string)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(uint256 p0, address p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,address,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,string,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,string,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,address,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, uint256 p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,address,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,string,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,string,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,address,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, string memory p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,string,address,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,string,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,string,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,address,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, bool p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,address,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,string,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,string,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,address,string)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(string memory p0, address p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(string,address,address,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,string,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,string,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,address,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, uint256 p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,address,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,string,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,string,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,address,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, string memory p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,address,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,string,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,string,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,address,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, bool p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,address,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,string,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,string,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,address,string)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(bool p0, address p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,address,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,string,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,string,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,address,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, uint256 p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,address,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,string,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,string,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,address,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, string memory p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,string,address,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,string,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,string,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,address,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, bool p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,address,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, uint256 p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,uint256,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, uint256 p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,uint256,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, uint256 p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,uint256,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, uint256 p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,uint256,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, string memory p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,string,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, string memory p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,string,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, string memory p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,string,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, string memory p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,string,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, bool p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,bool,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, bool p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,bool,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, bool p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,bool,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, bool p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,bool,address)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, address p2, uint256 p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,address,uint256)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, address p2, string memory p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,address,string)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, address p2, bool p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,address,bool)\", p0, p1, p2, p3));\n }\n\n function log(address p0, address p1, address p2, address p3) internal pure {\n _sendLogPayload(abi.encodeWithSignature(\"log(address,address,address,address)\", p0, p1, p2, p3));\n }\n}\n" + }, + "lib/forge-std/src/console2.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.4.22 <0.9.0;\n\nimport {console as console2} from \"./console.sol\";\n" + }, + "lib/forge-std/src/interfaces/IERC165.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.6.2;\n\ninterface IERC165 {\n /// @notice Query if a contract implements an interface\n /// @param interfaceID The interface identifier, as specified in ERC-165\n /// @dev Interface identification is specified in ERC-165. This function\n /// uses less than 30,000 gas.\n /// @return `true` if the contract implements `interfaceID` and\n /// `interfaceID` is not 0xffffffff, `false` otherwise\n function supportsInterface(bytes4 interfaceID) external view returns (bool);\n}\n" + }, + "lib/forge-std/src/interfaces/IERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.6.2;\n\n/// @dev Interface of the ERC20 standard as defined in the EIP.\n/// @dev This includes the optional name, symbol, and decimals metadata.\ninterface IERC20 {\n /// @dev Emitted when `value` tokens are moved from one account (`from`) to another (`to`).\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /// @dev Emitted when the allowance of a `spender` for an `owner` is set, where `value`\n /// is the new allowance.\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /// @notice Returns the amount of tokens in existence.\n function totalSupply() external view returns (uint256);\n\n /// @notice Returns the amount of tokens owned by `account`.\n function balanceOf(address account) external view returns (uint256);\n\n /// @notice Moves `amount` tokens from the caller's account to `to`.\n function transfer(address to, uint256 amount) external returns (bool);\n\n /// @notice Returns the remaining number of tokens that `spender` is allowed\n /// to spend on behalf of `owner`\n function allowance(address owner, address spender) external view returns (uint256);\n\n /// @notice Sets `amount` as the allowance of `spender` over the caller's tokens.\n /// @dev Be aware of front-running risks: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n function approve(address spender, uint256 amount) external returns (bool);\n\n /// @notice Moves `amount` tokens from `from` to `to` using the allowance mechanism.\n /// `amount` is then deducted from the caller's allowance.\n function transferFrom(address from, address to, uint256 amount) external returns (bool);\n\n /// @notice Returns the name of the token.\n function name() external view returns (string memory);\n\n /// @notice Returns the symbol of the token.\n function symbol() external view returns (string memory);\n\n /// @notice Returns the decimals places of the token.\n function decimals() external view returns (uint8);\n}\n" + }, + "lib/forge-std/src/interfaces/IERC721.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.6.2;\n\nimport \"./IERC165.sol\";\n\n/// @title ERC-721 Non-Fungible Token Standard\n/// @dev See https://eips.ethereum.org/EIPS/eip-721\n/// Note: the ERC-165 identifier for this interface is 0x80ac58cd.\ninterface IERC721 is IERC165 {\n /// @dev This emits when ownership of any NFT changes by any mechanism.\n /// This event emits when NFTs are created (`from` == 0) and destroyed\n /// (`to` == 0). Exception: during contract creation, any number of NFTs\n /// may be created and assigned without emitting Transfer. At the time of\n /// any transfer, the approved address for that NFT (if any) is reset to none.\n event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);\n\n /// @dev This emits when the approved address for an NFT is changed or\n /// reaffirmed. The zero address indicates there is no approved address.\n /// When a Transfer event emits, this also indicates that the approved\n /// address for that NFT (if any) is reset to none.\n event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId);\n\n /// @dev This emits when an operator is enabled or disabled for an owner.\n /// The operator can manage all NFTs of the owner.\n event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);\n\n /// @notice Count all NFTs assigned to an owner\n /// @dev NFTs assigned to the zero address are considered invalid, and this\n /// function throws for queries about the zero address.\n /// @param _owner An address for whom to query the balance\n /// @return The number of NFTs owned by `_owner`, possibly zero\n function balanceOf(address _owner) external view returns (uint256);\n\n /// @notice Find the owner of an NFT\n /// @dev NFTs assigned to zero address are considered invalid, and queries\n /// about them do throw.\n /// @param _tokenId The identifier for an NFT\n /// @return The address of the owner of the NFT\n function ownerOf(uint256 _tokenId) external view returns (address);\n\n /// @notice Transfers the ownership of an NFT from one address to another address\n /// @dev Throws unless `msg.sender` is the current owner, an authorized\n /// operator, or the approved address for this NFT. Throws if `_from` is\n /// not the current owner. Throws if `_to` is the zero address. Throws if\n /// `_tokenId` is not a valid NFT. When transfer is complete, this function\n /// checks if `_to` is a smart contract (code size > 0). If so, it calls\n /// `onERC721Received` on `_to` and throws if the return value is not\n /// `bytes4(keccak256(\"onERC721Received(address,address,uint256,bytes)\"))`.\n /// @param _from The current owner of the NFT\n /// @param _to The new owner\n /// @param _tokenId The NFT to transfer\n /// @param data Additional data with no specified format, sent in call to `_to`\n function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes calldata data) external payable;\n\n /// @notice Transfers the ownership of an NFT from one address to another address\n /// @dev This works identically to the other function with an extra data parameter,\n /// except this function just sets data to \"\".\n /// @param _from The current owner of the NFT\n /// @param _to The new owner\n /// @param _tokenId The NFT to transfer\n function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable;\n\n /// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE\n /// TO CONFIRM THAT `_to` IS CAPABLE OF RECEIVING NFTS OR ELSE\n /// THEY MAY BE PERMANENTLY LOST\n /// @dev Throws unless `msg.sender` is the current owner, an authorized\n /// operator, or the approved address for this NFT. Throws if `_from` is\n /// not the current owner. Throws if `_to` is the zero address. Throws if\n /// `_tokenId` is not a valid NFT.\n /// @param _from The current owner of the NFT\n /// @param _to The new owner\n /// @param _tokenId The NFT to transfer\n function transferFrom(address _from, address _to, uint256 _tokenId) external payable;\n\n /// @notice Change or reaffirm the approved address for an NFT\n /// @dev The zero address indicates there is no approved address.\n /// Throws unless `msg.sender` is the current NFT owner, or an authorized\n /// operator of the current owner.\n /// @param _approved The new approved NFT controller\n /// @param _tokenId The NFT to approve\n function approve(address _approved, uint256 _tokenId) external payable;\n\n /// @notice Enable or disable approval for a third party (\"operator\") to manage\n /// all of `msg.sender`'s assets\n /// @dev Emits the ApprovalForAll event. The contract MUST allow\n /// multiple operators per owner.\n /// @param _operator Address to add to the set of authorized operators\n /// @param _approved True if the operator is approved, false to revoke approval\n function setApprovalForAll(address _operator, bool _approved) external;\n\n /// @notice Get the approved address for a single NFT\n /// @dev Throws if `_tokenId` is not a valid NFT.\n /// @param _tokenId The NFT to find the approved address for\n /// @return The approved address for this NFT, or the zero address if there is none\n function getApproved(uint256 _tokenId) external view returns (address);\n\n /// @notice Query if an address is an authorized operator for another address\n /// @param _owner The address that owns the NFTs\n /// @param _operator The address that acts on behalf of the owner\n /// @return True if `_operator` is an approved operator for `_owner`, false otherwise\n function isApprovedForAll(address _owner, address _operator) external view returns (bool);\n}\n\n/// @dev Note: the ERC-165 identifier for this interface is 0x150b7a02.\ninterface IERC721TokenReceiver {\n /// @notice Handle the receipt of an NFT\n /// @dev The ERC721 smart contract calls this function on the recipient\n /// after a `transfer`. This function MAY throw to revert and reject the\n /// transfer. Return of other than the magic value MUST result in the\n /// transaction being reverted.\n /// Note: the contract address is always the message sender.\n /// @param _operator The address which called `safeTransferFrom` function\n /// @param _from The address which previously owned the token\n /// @param _tokenId The NFT identifier which is being transferred\n /// @param _data Additional data with no specified format\n /// @return `bytes4(keccak256(\"onERC721Received(address,address,uint256,bytes)\"))`\n /// unless throwing\n function onERC721Received(address _operator, address _from, uint256 _tokenId, bytes calldata _data)\n external\n returns (bytes4);\n}\n\n/// @title ERC-721 Non-Fungible Token Standard, optional metadata extension\n/// @dev See https://eips.ethereum.org/EIPS/eip-721\n/// Note: the ERC-165 identifier for this interface is 0x5b5e139f.\ninterface IERC721Metadata is IERC721 {\n /// @notice A descriptive name for a collection of NFTs in this contract\n function name() external view returns (string memory _name);\n\n /// @notice An abbreviated name for NFTs in this contract\n function symbol() external view returns (string memory _symbol);\n\n /// @notice A distinct Uniform Resource Identifier (URI) for a given asset.\n /// @dev Throws if `_tokenId` is not a valid NFT. URIs are defined in RFC\n /// 3986. The URI may point to a JSON file that conforms to the \"ERC721\n /// Metadata JSON Schema\".\n function tokenURI(uint256 _tokenId) external view returns (string memory);\n}\n\n/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension\n/// @dev See https://eips.ethereum.org/EIPS/eip-721\n/// Note: the ERC-165 identifier for this interface is 0x780e9d63.\ninterface IERC721Enumerable is IERC721 {\n /// @notice Count NFTs tracked by this contract\n /// @return A count of valid NFTs tracked by this contract, where each one of\n /// them has an assigned and queryable owner not equal to the zero address\n function totalSupply() external view returns (uint256);\n\n /// @notice Enumerate valid NFTs\n /// @dev Throws if `_index` >= `totalSupply()`.\n /// @param _index A counter less than `totalSupply()`\n /// @return The token identifier for the `_index`th NFT,\n /// (sort order not specified)\n function tokenByIndex(uint256 _index) external view returns (uint256);\n\n /// @notice Enumerate NFTs assigned to an owner\n /// @dev Throws if `_index` >= `balanceOf(_owner)` or if\n /// `_owner` is the zero address, representing invalid NFTs.\n /// @param _owner An address where we are interested in NFTs owned by them\n /// @param _index A counter less than `balanceOf(_owner)`\n /// @return The token identifier for the `_index`th NFT assigned to `_owner`,\n /// (sort order not specified)\n function tokenOfOwnerByIndex(address _owner, uint256 _index) external view returns (uint256);\n}\n" + }, + "lib/forge-std/src/interfaces/IMulticall3.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.6.2 <0.9.0;\n\npragma experimental ABIEncoderV2;\n\ninterface IMulticall3 {\n struct Call {\n address target;\n bytes callData;\n }\n\n struct Call3 {\n address target;\n bool allowFailure;\n bytes callData;\n }\n\n struct Call3Value {\n address target;\n bool allowFailure;\n uint256 value;\n bytes callData;\n }\n\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function aggregate(Call[] calldata calls)\n external\n payable\n returns (uint256 blockNumber, bytes[] memory returnData);\n\n function aggregate3(Call3[] calldata calls) external payable returns (Result[] memory returnData);\n\n function aggregate3Value(Call3Value[] calldata calls) external payable returns (Result[] memory returnData);\n\n function blockAndAggregate(Call[] calldata calls)\n external\n payable\n returns (uint256 blockNumber, bytes32 blockHash, Result[] memory returnData);\n\n function getBasefee() external view returns (uint256 basefee);\n\n function getBlockHash(uint256 blockNumber) external view returns (bytes32 blockHash);\n\n function getBlockNumber() external view returns (uint256 blockNumber);\n\n function getChainId() external view returns (uint256 chainid);\n\n function getCurrentBlockCoinbase() external view returns (address coinbase);\n\n function getCurrentBlockDifficulty() external view returns (uint256 difficulty);\n\n function getCurrentBlockGasLimit() external view returns (uint256 gaslimit);\n\n function getCurrentBlockTimestamp() external view returns (uint256 timestamp);\n\n function getEthBalance(address addr) external view returns (uint256 balance);\n\n function getLastBlockHash() external view returns (bytes32 blockHash);\n\n function tryAggregate(bool requireSuccess, Call[] calldata calls)\n external\n payable\n returns (Result[] memory returnData);\n\n function tryBlockAndAggregate(bool requireSuccess, Call[] calldata calls)\n external\n payable\n returns (uint256 blockNumber, bytes32 blockHash, Result[] memory returnData);\n}\n" + }, + "lib/forge-std/src/mocks/MockERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.6.2 <0.9.0;\n\nimport {IERC20} from \"../interfaces/IERC20.sol\";\n\n/// @notice This is a mock contract of the ERC20 standard for testing purposes only, it SHOULD NOT be used in production.\n/// @dev Forked from: https://github.com/transmissions11/solmate/blob/0384dbaaa4fcb5715738a9254a7c0a4cb62cf458/src/tokens/ERC20.sol\ncontract MockERC20 is IERC20 {\n /*//////////////////////////////////////////////////////////////\n METADATA STORAGE\n //////////////////////////////////////////////////////////////*/\n\n string internal _name;\n\n string internal _symbol;\n\n uint8 internal _decimals;\n\n function name() external view override returns (string memory) {\n return _name;\n }\n\n function symbol() external view override returns (string memory) {\n return _symbol;\n }\n\n function decimals() external view override returns (uint8) {\n return _decimals;\n }\n\n /*//////////////////////////////////////////////////////////////\n ERC20 STORAGE\n //////////////////////////////////////////////////////////////*/\n\n uint256 internal _totalSupply;\n\n mapping(address => uint256) internal _balanceOf;\n\n mapping(address => mapping(address => uint256)) internal _allowance;\n\n function totalSupply() external view override returns (uint256) {\n return _totalSupply;\n }\n\n function balanceOf(address owner) external view override returns (uint256) {\n return _balanceOf[owner];\n }\n\n function allowance(address owner, address spender) external view override returns (uint256) {\n return _allowance[owner][spender];\n }\n\n /*//////////////////////////////////////////////////////////////\n EIP-2612 STORAGE\n //////////////////////////////////////////////////////////////*/\n\n uint256 internal INITIAL_CHAIN_ID;\n\n bytes32 internal INITIAL_DOMAIN_SEPARATOR;\n\n mapping(address => uint256) public nonces;\n\n /*//////////////////////////////////////////////////////////////\n INITIALIZE\n //////////////////////////////////////////////////////////////*/\n\n /// @dev A bool to track whether the contract has been initialized.\n bool private initialized;\n\n /// @dev To hide constructor warnings across solc versions due to different constructor visibility requirements and\n /// syntaxes, we add an initialization function that can be called only once.\n function initialize(string memory name_, string memory symbol_, uint8 decimals_) public {\n require(!initialized, \"ALREADY_INITIALIZED\");\n\n _name = name_;\n _symbol = symbol_;\n _decimals = decimals_;\n\n INITIAL_CHAIN_ID = _pureChainId();\n INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();\n\n initialized = true;\n }\n\n /*//////////////////////////////////////////////////////////////\n ERC20 LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n _allowance[msg.sender][spender] = amount;\n\n emit Approval(msg.sender, spender, amount);\n\n return true;\n }\n\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n _balanceOf[msg.sender] = _sub(_balanceOf[msg.sender], amount);\n _balanceOf[to] = _add(_balanceOf[to], amount);\n\n emit Transfer(msg.sender, to, amount);\n\n return true;\n }\n\n function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) {\n uint256 allowed = _allowance[from][msg.sender]; // Saves gas for limited approvals.\n\n if (allowed != ~uint256(0)) _allowance[from][msg.sender] = _sub(allowed, amount);\n\n _balanceOf[from] = _sub(_balanceOf[from], amount);\n _balanceOf[to] = _add(_balanceOf[to], amount);\n\n emit Transfer(from, to, amount);\n\n return true;\n }\n\n /*//////////////////////////////////////////////////////////////\n EIP-2612 LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)\n public\n virtual\n {\n require(deadline >= block.timestamp, \"PERMIT_DEADLINE_EXPIRED\");\n\n address recoveredAddress = ecrecover(\n keccak256(\n abi.encodePacked(\n \"\\x19\\x01\",\n DOMAIN_SEPARATOR(),\n keccak256(\n abi.encode(\n keccak256(\n \"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\"\n ),\n owner,\n spender,\n value,\n nonces[owner]++,\n deadline\n )\n )\n )\n ),\n v,\n r,\n s\n );\n\n require(recoveredAddress != address(0) && recoveredAddress == owner, \"INVALID_SIGNER\");\n\n _allowance[recoveredAddress][spender] = value;\n\n emit Approval(owner, spender, value);\n }\n\n function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {\n return _pureChainId() == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();\n }\n\n function computeDomainSeparator() internal view virtual returns (bytes32) {\n return keccak256(\n abi.encode(\n keccak256(\"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\"),\n keccak256(bytes(_name)),\n keccak256(\"1\"),\n _pureChainId(),\n address(this)\n )\n );\n }\n\n /*//////////////////////////////////////////////////////////////\n INTERNAL MINT/BURN LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function _mint(address to, uint256 amount) internal virtual {\n _totalSupply = _add(_totalSupply, amount);\n _balanceOf[to] = _add(_balanceOf[to], amount);\n\n emit Transfer(address(0), to, amount);\n }\n\n function _burn(address from, uint256 amount) internal virtual {\n _balanceOf[from] = _sub(_balanceOf[from], amount);\n _totalSupply = _sub(_totalSupply, amount);\n\n emit Transfer(from, address(0), amount);\n }\n\n /*//////////////////////////////////////////////////////////////\n INTERNAL SAFE MATH LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function _add(uint256 a, uint256 b) internal pure returns (uint256) {\n uint256 c = a + b;\n require(c >= a, \"ERC20: addition overflow\");\n return c;\n }\n\n function _sub(uint256 a, uint256 b) internal pure returns (uint256) {\n require(a >= b, \"ERC20: subtraction underflow\");\n return a - b;\n }\n\n /*//////////////////////////////////////////////////////////////\n HELPERS\n //////////////////////////////////////////////////////////////*/\n\n // We use this complex approach of `_viewChainId` and `_pureChainId` to ensure there are no\n // compiler warnings when accessing chain ID in any solidity version supported by forge-std. We\n // can't simply access the chain ID in a normal view or pure function because the solc View Pure\n // Checker changed `chainid` from pure to view in 0.8.0.\n function _viewChainId() private view returns (uint256 chainId) {\n // Assembly required since `block.chainid` was introduced in 0.8.0.\n assembly {\n chainId := chainid()\n }\n\n address(this); // Silence warnings in older Solc versions.\n }\n\n function _pureChainId() private pure returns (uint256 chainId) {\n function() internal view returns (uint256) fnIn = _viewChainId;\n function() internal pure returns (uint256) pureChainId;\n assembly {\n pureChainId := fnIn\n }\n chainId = pureChainId();\n }\n}\n" + }, + "lib/forge-std/src/mocks/MockERC721.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.6.2 <0.9.0;\n\nimport {IERC721Metadata, IERC721TokenReceiver} from \"../interfaces/IERC721.sol\";\n\n/// @notice This is a mock contract of the ERC721 standard for testing purposes only, it SHOULD NOT be used in production.\n/// @dev Forked from: https://github.com/transmissions11/solmate/blob/0384dbaaa4fcb5715738a9254a7c0a4cb62cf458/src/tokens/ERC721.sol\ncontract MockERC721 is IERC721Metadata {\n /*//////////////////////////////////////////////////////////////\n METADATA STORAGE/LOGIC\n //////////////////////////////////////////////////////////////*/\n\n string internal _name;\n\n string internal _symbol;\n\n function name() external view override returns (string memory) {\n return _name;\n }\n\n function symbol() external view override returns (string memory) {\n return _symbol;\n }\n\n function tokenURI(uint256 id) public view virtual override returns (string memory) {}\n\n /*//////////////////////////////////////////////////////////////\n ERC721 BALANCE/OWNER STORAGE\n //////////////////////////////////////////////////////////////*/\n\n mapping(uint256 => address) internal _ownerOf;\n\n mapping(address => uint256) internal _balanceOf;\n\n function ownerOf(uint256 id) public view virtual override returns (address owner) {\n require((owner = _ownerOf[id]) != address(0), \"NOT_MINTED\");\n }\n\n function balanceOf(address owner) public view virtual override returns (uint256) {\n require(owner != address(0), \"ZERO_ADDRESS\");\n\n return _balanceOf[owner];\n }\n\n /*//////////////////////////////////////////////////////////////\n ERC721 APPROVAL STORAGE\n //////////////////////////////////////////////////////////////*/\n\n mapping(uint256 => address) internal _getApproved;\n\n mapping(address => mapping(address => bool)) internal _isApprovedForAll;\n\n function getApproved(uint256 id) public view virtual override returns (address) {\n return _getApproved[id];\n }\n\n function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {\n return _isApprovedForAll[owner][operator];\n }\n\n /*//////////////////////////////////////////////////////////////\n INITIALIZE\n //////////////////////////////////////////////////////////////*/\n\n /// @dev A bool to track whether the contract has been initialized.\n bool private initialized;\n\n /// @dev To hide constructor warnings across solc versions due to different constructor visibility requirements and\n /// syntaxes, we add an initialization function that can be called only once.\n function initialize(string memory name_, string memory symbol_) public {\n require(!initialized, \"ALREADY_INITIALIZED\");\n\n _name = name_;\n _symbol = symbol_;\n\n initialized = true;\n }\n\n /*//////////////////////////////////////////////////////////////\n ERC721 LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function approve(address spender, uint256 id) public payable virtual override {\n address owner = _ownerOf[id];\n\n require(msg.sender == owner || _isApprovedForAll[owner][msg.sender], \"NOT_AUTHORIZED\");\n\n _getApproved[id] = spender;\n\n emit Approval(owner, spender, id);\n }\n\n function setApprovalForAll(address operator, bool approved) public virtual override {\n _isApprovedForAll[msg.sender][operator] = approved;\n\n emit ApprovalForAll(msg.sender, operator, approved);\n }\n\n function transferFrom(address from, address to, uint256 id) public payable virtual override {\n require(from == _ownerOf[id], \"WRONG_FROM\");\n\n require(to != address(0), \"INVALID_RECIPIENT\");\n\n require(\n msg.sender == from || _isApprovedForAll[from][msg.sender] || msg.sender == _getApproved[id],\n \"NOT_AUTHORIZED\"\n );\n\n // Underflow of the sender's balance is impossible because we check for\n // ownership above and the recipient's balance can't realistically overflow.\n _balanceOf[from]--;\n\n _balanceOf[to]++;\n\n _ownerOf[id] = to;\n\n delete _getApproved[id];\n\n emit Transfer(from, to, id);\n }\n\n function safeTransferFrom(address from, address to, uint256 id) public payable virtual override {\n transferFrom(from, to, id);\n\n require(\n !_isContract(to)\n || IERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, \"\")\n == IERC721TokenReceiver.onERC721Received.selector,\n \"UNSAFE_RECIPIENT\"\n );\n }\n\n function safeTransferFrom(address from, address to, uint256 id, bytes memory data)\n public\n payable\n virtual\n override\n {\n transferFrom(from, to, id);\n\n require(\n !_isContract(to)\n || IERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, data)\n == IERC721TokenReceiver.onERC721Received.selector,\n \"UNSAFE_RECIPIENT\"\n );\n }\n\n /*//////////////////////////////////////////////////////////////\n ERC165 LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == 0x01ffc9a7 // ERC165 Interface ID for ERC165\n || interfaceId == 0x80ac58cd // ERC165 Interface ID for ERC721\n || interfaceId == 0x5b5e139f; // ERC165 Interface ID for ERC721Metadata\n }\n\n /*//////////////////////////////////////////////////////////////\n INTERNAL MINT/BURN LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function _mint(address to, uint256 id) internal virtual {\n require(to != address(0), \"INVALID_RECIPIENT\");\n\n require(_ownerOf[id] == address(0), \"ALREADY_MINTED\");\n\n // Counter overflow is incredibly unrealistic.\n\n _balanceOf[to]++;\n\n _ownerOf[id] = to;\n\n emit Transfer(address(0), to, id);\n }\n\n function _burn(uint256 id) internal virtual {\n address owner = _ownerOf[id];\n\n require(owner != address(0), \"NOT_MINTED\");\n\n _balanceOf[owner]--;\n\n delete _ownerOf[id];\n\n delete _getApproved[id];\n\n emit Transfer(owner, address(0), id);\n }\n\n /*//////////////////////////////////////////////////////////////\n INTERNAL SAFE MINT LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function _safeMint(address to, uint256 id) internal virtual {\n _mint(to, id);\n\n require(\n !_isContract(to)\n || IERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, \"\")\n == IERC721TokenReceiver.onERC721Received.selector,\n \"UNSAFE_RECIPIENT\"\n );\n }\n\n function _safeMint(address to, uint256 id, bytes memory data) internal virtual {\n _mint(to, id);\n\n require(\n !_isContract(to)\n || IERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, data)\n == IERC721TokenReceiver.onERC721Received.selector,\n \"UNSAFE_RECIPIENT\"\n );\n }\n\n /*//////////////////////////////////////////////////////////////\n HELPERS\n //////////////////////////////////////////////////////////////*/\n\n function _isContract(address _addr) private view returns (bool) {\n uint256 codeLength;\n\n // Assembly required for versions < 0.8.0 to check extcodesize.\n assembly {\n codeLength := extcodesize(_addr)\n }\n\n return codeLength > 0;\n }\n}\n" + }, + "lib/forge-std/src/safeconsole.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.6.2 <0.9.0;\n\n/// @author philogy \n/// @dev Code generated automatically by script.\nlibrary safeconsole {\n uint256 constant CONSOLE_ADDR = 0x000000000000000000000000000000000000000000636F6e736F6c652e6c6f67;\n\n // Credit to [0age](https://twitter.com/z0age/status/1654922202930888704) and [0xdapper](https://github.com/foundry-rs/forge-std/pull/374)\n // for the view-to-pure log trick.\n function _sendLogPayload(uint256 offset, uint256 size) private pure {\n function(uint256, uint256) internal view fnIn = _sendLogPayloadView;\n function(uint256, uint256) internal pure pureSendLogPayload;\n /// @solidity memory-safe-assembly\n assembly {\n pureSendLogPayload := fnIn\n }\n pureSendLogPayload(offset, size);\n }\n\n function _sendLogPayloadView(uint256 offset, uint256 size) private view {\n /// @solidity memory-safe-assembly\n assembly {\n pop(staticcall(gas(), CONSOLE_ADDR, offset, size, 0x0, 0x0))\n }\n }\n\n function _memcopy(uint256 fromOffset, uint256 toOffset, uint256 length) private pure {\n function(uint256, uint256, uint256) internal view fnIn = _memcopyView;\n function(uint256, uint256, uint256) internal pure pureMemcopy;\n /// @solidity memory-safe-assembly\n assembly {\n pureMemcopy := fnIn\n }\n pureMemcopy(fromOffset, toOffset, length);\n }\n\n function _memcopyView(uint256 fromOffset, uint256 toOffset, uint256 length) private view {\n /// @solidity memory-safe-assembly\n assembly {\n pop(staticcall(gas(), 0x4, fromOffset, length, toOffset, length))\n }\n }\n\n function logMemory(uint256 offset, uint256 length) internal pure {\n if (offset >= 0x60) {\n // Sufficient memory before slice to prepare call header.\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(sub(offset, 0x60))\n m1 := mload(sub(offset, 0x40))\n m2 := mload(sub(offset, 0x20))\n // Selector of `log(bytes)`.\n mstore(sub(offset, 0x60), 0x0be77f56)\n mstore(sub(offset, 0x40), 0x20)\n mstore(sub(offset, 0x20), length)\n }\n _sendLogPayload(offset - 0x44, length + 0x44);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(sub(offset, 0x60), m0)\n mstore(sub(offset, 0x40), m1)\n mstore(sub(offset, 0x20), m2)\n }\n } else {\n // Insufficient space, so copy slice forward, add header and reverse.\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n uint256 endOffset = offset + length;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(add(endOffset, 0x00))\n m1 := mload(add(endOffset, 0x20))\n m2 := mload(add(endOffset, 0x40))\n }\n _memcopy(offset, offset + 0x60, length);\n /// @solidity memory-safe-assembly\n assembly {\n // Selector of `log(bytes)`.\n mstore(add(offset, 0x00), 0x0be77f56)\n mstore(add(offset, 0x20), 0x20)\n mstore(add(offset, 0x40), length)\n }\n _sendLogPayload(offset + 0x1c, length + 0x44);\n _memcopy(offset + 0x60, offset, length);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(add(endOffset, 0x00), m0)\n mstore(add(endOffset, 0x20), m1)\n mstore(add(endOffset, 0x40), m2)\n }\n }\n }\n\n function log(address p0) internal pure {\n bytes32 m0;\n bytes32 m1;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n // Selector of `log(address)`.\n mstore(0x00, 0x2c2ecbc2)\n mstore(0x20, p0)\n }\n _sendLogPayload(0x1c, 0x24);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n }\n }\n\n function log(bool p0) internal pure {\n bytes32 m0;\n bytes32 m1;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n // Selector of `log(bool)`.\n mstore(0x00, 0x32458eed)\n mstore(0x20, p0)\n }\n _sendLogPayload(0x1c, 0x24);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n }\n }\n\n function log(uint256 p0) internal pure {\n bytes32 m0;\n bytes32 m1;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n // Selector of `log(uint256)`.\n mstore(0x00, 0xf82c50f1)\n mstore(0x20, p0)\n }\n _sendLogPayload(0x1c, 0x24);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n }\n }\n\n function log(bytes32 p0) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n // Selector of `log(string)`.\n mstore(0x00, 0x41304fac)\n mstore(0x20, 0x20)\n writeString(0x40, p0)\n }\n _sendLogPayload(0x1c, 0x64);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n }\n }\n\n function log(address p0, address p1) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n // Selector of `log(address,address)`.\n mstore(0x00, 0xdaf0d4aa)\n mstore(0x20, p0)\n mstore(0x40, p1)\n }\n _sendLogPayload(0x1c, 0x44);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n }\n }\n\n function log(address p0, bool p1) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n // Selector of `log(address,bool)`.\n mstore(0x00, 0x75b605d3)\n mstore(0x20, p0)\n mstore(0x40, p1)\n }\n _sendLogPayload(0x1c, 0x44);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n }\n }\n\n function log(address p0, uint256 p1) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n // Selector of `log(address,uint256)`.\n mstore(0x00, 0x8309e8a8)\n mstore(0x20, p0)\n mstore(0x40, p1)\n }\n _sendLogPayload(0x1c, 0x44);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n }\n }\n\n function log(address p0, bytes32 p1) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(address,string)`.\n mstore(0x00, 0x759f86bb)\n mstore(0x20, p0)\n mstore(0x40, 0x40)\n writeString(0x60, p1)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(bool p0, address p1) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n // Selector of `log(bool,address)`.\n mstore(0x00, 0x853c4849)\n mstore(0x20, p0)\n mstore(0x40, p1)\n }\n _sendLogPayload(0x1c, 0x44);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n }\n }\n\n function log(bool p0, bool p1) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n // Selector of `log(bool,bool)`.\n mstore(0x00, 0x2a110e83)\n mstore(0x20, p0)\n mstore(0x40, p1)\n }\n _sendLogPayload(0x1c, 0x44);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n }\n }\n\n function log(bool p0, uint256 p1) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n // Selector of `log(bool,uint256)`.\n mstore(0x00, 0x399174d3)\n mstore(0x20, p0)\n mstore(0x40, p1)\n }\n _sendLogPayload(0x1c, 0x44);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n }\n }\n\n function log(bool p0, bytes32 p1) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(bool,string)`.\n mstore(0x00, 0x8feac525)\n mstore(0x20, p0)\n mstore(0x40, 0x40)\n writeString(0x60, p1)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(uint256 p0, address p1) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n // Selector of `log(uint256,address)`.\n mstore(0x00, 0x69276c86)\n mstore(0x20, p0)\n mstore(0x40, p1)\n }\n _sendLogPayload(0x1c, 0x44);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n }\n }\n\n function log(uint256 p0, bool p1) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n // Selector of `log(uint256,bool)`.\n mstore(0x00, 0x1c9d7eb3)\n mstore(0x20, p0)\n mstore(0x40, p1)\n }\n _sendLogPayload(0x1c, 0x44);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n }\n }\n\n function log(uint256 p0, uint256 p1) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n // Selector of `log(uint256,uint256)`.\n mstore(0x00, 0xf666715a)\n mstore(0x20, p0)\n mstore(0x40, p1)\n }\n _sendLogPayload(0x1c, 0x44);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n }\n }\n\n function log(uint256 p0, bytes32 p1) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(uint256,string)`.\n mstore(0x00, 0x643fd0df)\n mstore(0x20, p0)\n mstore(0x40, 0x40)\n writeString(0x60, p1)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(bytes32 p0, address p1) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(string,address)`.\n mstore(0x00, 0x319af333)\n mstore(0x20, 0x40)\n mstore(0x40, p1)\n writeString(0x60, p0)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(bytes32 p0, bool p1) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(string,bool)`.\n mstore(0x00, 0xc3b55635)\n mstore(0x20, 0x40)\n mstore(0x40, p1)\n writeString(0x60, p0)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(bytes32 p0, uint256 p1) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(string,uint256)`.\n mstore(0x00, 0xb60e72cc)\n mstore(0x20, 0x40)\n mstore(0x40, p1)\n writeString(0x60, p0)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(bytes32 p0, bytes32 p1) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(string,string)`.\n mstore(0x00, 0x4b5c4277)\n mstore(0x20, 0x40)\n mstore(0x40, 0x80)\n writeString(0x60, p0)\n writeString(0xa0, p1)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(address p0, address p1, address p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n // Selector of `log(address,address,address)`.\n mstore(0x00, 0x018c84c2)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n }\n _sendLogPayload(0x1c, 0x64);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n }\n }\n\n function log(address p0, address p1, bool p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n // Selector of `log(address,address,bool)`.\n mstore(0x00, 0xf2a66286)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n }\n _sendLogPayload(0x1c, 0x64);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n }\n }\n\n function log(address p0, address p1, uint256 p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n // Selector of `log(address,address,uint256)`.\n mstore(0x00, 0x17fe6185)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n }\n _sendLogPayload(0x1c, 0x64);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n }\n }\n\n function log(address p0, address p1, bytes32 p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n // Selector of `log(address,address,string)`.\n mstore(0x00, 0x007150be)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, 0x60)\n writeString(0x80, p2)\n }\n _sendLogPayload(0x1c, 0xa4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n }\n }\n\n function log(address p0, bool p1, address p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n // Selector of `log(address,bool,address)`.\n mstore(0x00, 0xf11699ed)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n }\n _sendLogPayload(0x1c, 0x64);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n }\n }\n\n function log(address p0, bool p1, bool p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n // Selector of `log(address,bool,bool)`.\n mstore(0x00, 0xeb830c92)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n }\n _sendLogPayload(0x1c, 0x64);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n }\n }\n\n function log(address p0, bool p1, uint256 p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n // Selector of `log(address,bool,uint256)`.\n mstore(0x00, 0x9c4f99fb)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n }\n _sendLogPayload(0x1c, 0x64);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n }\n }\n\n function log(address p0, bool p1, bytes32 p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n // Selector of `log(address,bool,string)`.\n mstore(0x00, 0x212255cc)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, 0x60)\n writeString(0x80, p2)\n }\n _sendLogPayload(0x1c, 0xa4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n }\n }\n\n function log(address p0, uint256 p1, address p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n // Selector of `log(address,uint256,address)`.\n mstore(0x00, 0x7bc0d848)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n }\n _sendLogPayload(0x1c, 0x64);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n }\n }\n\n function log(address p0, uint256 p1, bool p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n // Selector of `log(address,uint256,bool)`.\n mstore(0x00, 0x678209a8)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n }\n _sendLogPayload(0x1c, 0x64);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n }\n }\n\n function log(address p0, uint256 p1, uint256 p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n // Selector of `log(address,uint256,uint256)`.\n mstore(0x00, 0xb69bcaf6)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n }\n _sendLogPayload(0x1c, 0x64);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n }\n }\n\n function log(address p0, uint256 p1, bytes32 p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n // Selector of `log(address,uint256,string)`.\n mstore(0x00, 0xa1f2e8aa)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, 0x60)\n writeString(0x80, p2)\n }\n _sendLogPayload(0x1c, 0xa4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n }\n }\n\n function log(address p0, bytes32 p1, address p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n // Selector of `log(address,string,address)`.\n mstore(0x00, 0xf08744e8)\n mstore(0x20, p0)\n mstore(0x40, 0x60)\n mstore(0x60, p2)\n writeString(0x80, p1)\n }\n _sendLogPayload(0x1c, 0xa4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n }\n }\n\n function log(address p0, bytes32 p1, bool p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n // Selector of `log(address,string,bool)`.\n mstore(0x00, 0xcf020fb1)\n mstore(0x20, p0)\n mstore(0x40, 0x60)\n mstore(0x60, p2)\n writeString(0x80, p1)\n }\n _sendLogPayload(0x1c, 0xa4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n }\n }\n\n function log(address p0, bytes32 p1, uint256 p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n // Selector of `log(address,string,uint256)`.\n mstore(0x00, 0x67dd6ff1)\n mstore(0x20, p0)\n mstore(0x40, 0x60)\n mstore(0x60, p2)\n writeString(0x80, p1)\n }\n _sendLogPayload(0x1c, 0xa4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n }\n }\n\n function log(address p0, bytes32 p1, bytes32 p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n // Selector of `log(address,string,string)`.\n mstore(0x00, 0xfb772265)\n mstore(0x20, p0)\n mstore(0x40, 0x60)\n mstore(0x60, 0xa0)\n writeString(0x80, p1)\n writeString(0xc0, p2)\n }\n _sendLogPayload(0x1c, 0xe4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n }\n }\n\n function log(bool p0, address p1, address p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n // Selector of `log(bool,address,address)`.\n mstore(0x00, 0xd2763667)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n }\n _sendLogPayload(0x1c, 0x64);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n }\n }\n\n function log(bool p0, address p1, bool p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n // Selector of `log(bool,address,bool)`.\n mstore(0x00, 0x18c9c746)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n }\n _sendLogPayload(0x1c, 0x64);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n }\n }\n\n function log(bool p0, address p1, uint256 p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n // Selector of `log(bool,address,uint256)`.\n mstore(0x00, 0x5f7b9afb)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n }\n _sendLogPayload(0x1c, 0x64);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n }\n }\n\n function log(bool p0, address p1, bytes32 p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n // Selector of `log(bool,address,string)`.\n mstore(0x00, 0xde9a9270)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, 0x60)\n writeString(0x80, p2)\n }\n _sendLogPayload(0x1c, 0xa4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n }\n }\n\n function log(bool p0, bool p1, address p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n // Selector of `log(bool,bool,address)`.\n mstore(0x00, 0x1078f68d)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n }\n _sendLogPayload(0x1c, 0x64);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n }\n }\n\n function log(bool p0, bool p1, bool p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n // Selector of `log(bool,bool,bool)`.\n mstore(0x00, 0x50709698)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n }\n _sendLogPayload(0x1c, 0x64);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n }\n }\n\n function log(bool p0, bool p1, uint256 p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n // Selector of `log(bool,bool,uint256)`.\n mstore(0x00, 0x12f21602)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n }\n _sendLogPayload(0x1c, 0x64);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n }\n }\n\n function log(bool p0, bool p1, bytes32 p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n // Selector of `log(bool,bool,string)`.\n mstore(0x00, 0x2555fa46)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, 0x60)\n writeString(0x80, p2)\n }\n _sendLogPayload(0x1c, 0xa4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n }\n }\n\n function log(bool p0, uint256 p1, address p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n // Selector of `log(bool,uint256,address)`.\n mstore(0x00, 0x088ef9d2)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n }\n _sendLogPayload(0x1c, 0x64);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n }\n }\n\n function log(bool p0, uint256 p1, bool p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n // Selector of `log(bool,uint256,bool)`.\n mstore(0x00, 0xe8defba9)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n }\n _sendLogPayload(0x1c, 0x64);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n }\n }\n\n function log(bool p0, uint256 p1, uint256 p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n // Selector of `log(bool,uint256,uint256)`.\n mstore(0x00, 0x37103367)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n }\n _sendLogPayload(0x1c, 0x64);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n }\n }\n\n function log(bool p0, uint256 p1, bytes32 p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n // Selector of `log(bool,uint256,string)`.\n mstore(0x00, 0xc3fc3970)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, 0x60)\n writeString(0x80, p2)\n }\n _sendLogPayload(0x1c, 0xa4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n }\n }\n\n function log(bool p0, bytes32 p1, address p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n // Selector of `log(bool,string,address)`.\n mstore(0x00, 0x9591b953)\n mstore(0x20, p0)\n mstore(0x40, 0x60)\n mstore(0x60, p2)\n writeString(0x80, p1)\n }\n _sendLogPayload(0x1c, 0xa4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n }\n }\n\n function log(bool p0, bytes32 p1, bool p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n // Selector of `log(bool,string,bool)`.\n mstore(0x00, 0xdbb4c247)\n mstore(0x20, p0)\n mstore(0x40, 0x60)\n mstore(0x60, p2)\n writeString(0x80, p1)\n }\n _sendLogPayload(0x1c, 0xa4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n }\n }\n\n function log(bool p0, bytes32 p1, uint256 p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n // Selector of `log(bool,string,uint256)`.\n mstore(0x00, 0x1093ee11)\n mstore(0x20, p0)\n mstore(0x40, 0x60)\n mstore(0x60, p2)\n writeString(0x80, p1)\n }\n _sendLogPayload(0x1c, 0xa4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n }\n }\n\n function log(bool p0, bytes32 p1, bytes32 p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n // Selector of `log(bool,string,string)`.\n mstore(0x00, 0xb076847f)\n mstore(0x20, p0)\n mstore(0x40, 0x60)\n mstore(0x60, 0xa0)\n writeString(0x80, p1)\n writeString(0xc0, p2)\n }\n _sendLogPayload(0x1c, 0xe4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n }\n }\n\n function log(uint256 p0, address p1, address p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n // Selector of `log(uint256,address,address)`.\n mstore(0x00, 0xbcfd9be0)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n }\n _sendLogPayload(0x1c, 0x64);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n }\n }\n\n function log(uint256 p0, address p1, bool p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n // Selector of `log(uint256,address,bool)`.\n mstore(0x00, 0x9b6ec042)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n }\n _sendLogPayload(0x1c, 0x64);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n }\n }\n\n function log(uint256 p0, address p1, uint256 p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n // Selector of `log(uint256,address,uint256)`.\n mstore(0x00, 0x5a9b5ed5)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n }\n _sendLogPayload(0x1c, 0x64);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n }\n }\n\n function log(uint256 p0, address p1, bytes32 p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n // Selector of `log(uint256,address,string)`.\n mstore(0x00, 0x63cb41f9)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, 0x60)\n writeString(0x80, p2)\n }\n _sendLogPayload(0x1c, 0xa4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n }\n }\n\n function log(uint256 p0, bool p1, address p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n // Selector of `log(uint256,bool,address)`.\n mstore(0x00, 0x35085f7b)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n }\n _sendLogPayload(0x1c, 0x64);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n }\n }\n\n function log(uint256 p0, bool p1, bool p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n // Selector of `log(uint256,bool,bool)`.\n mstore(0x00, 0x20718650)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n }\n _sendLogPayload(0x1c, 0x64);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n }\n }\n\n function log(uint256 p0, bool p1, uint256 p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n // Selector of `log(uint256,bool,uint256)`.\n mstore(0x00, 0x20098014)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n }\n _sendLogPayload(0x1c, 0x64);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n }\n }\n\n function log(uint256 p0, bool p1, bytes32 p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n // Selector of `log(uint256,bool,string)`.\n mstore(0x00, 0x85775021)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, 0x60)\n writeString(0x80, p2)\n }\n _sendLogPayload(0x1c, 0xa4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n }\n }\n\n function log(uint256 p0, uint256 p1, address p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n // Selector of `log(uint256,uint256,address)`.\n mstore(0x00, 0x5c96b331)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n }\n _sendLogPayload(0x1c, 0x64);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n }\n }\n\n function log(uint256 p0, uint256 p1, bool p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n // Selector of `log(uint256,uint256,bool)`.\n mstore(0x00, 0x4766da72)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n }\n _sendLogPayload(0x1c, 0x64);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n }\n }\n\n function log(uint256 p0, uint256 p1, uint256 p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n // Selector of `log(uint256,uint256,uint256)`.\n mstore(0x00, 0xd1ed7a3c)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n }\n _sendLogPayload(0x1c, 0x64);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n }\n }\n\n function log(uint256 p0, uint256 p1, bytes32 p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n // Selector of `log(uint256,uint256,string)`.\n mstore(0x00, 0x71d04af2)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, 0x60)\n writeString(0x80, p2)\n }\n _sendLogPayload(0x1c, 0xa4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n }\n }\n\n function log(uint256 p0, bytes32 p1, address p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n // Selector of `log(uint256,string,address)`.\n mstore(0x00, 0x7afac959)\n mstore(0x20, p0)\n mstore(0x40, 0x60)\n mstore(0x60, p2)\n writeString(0x80, p1)\n }\n _sendLogPayload(0x1c, 0xa4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n }\n }\n\n function log(uint256 p0, bytes32 p1, bool p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n // Selector of `log(uint256,string,bool)`.\n mstore(0x00, 0x4ceda75a)\n mstore(0x20, p0)\n mstore(0x40, 0x60)\n mstore(0x60, p2)\n writeString(0x80, p1)\n }\n _sendLogPayload(0x1c, 0xa4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n }\n }\n\n function log(uint256 p0, bytes32 p1, uint256 p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n // Selector of `log(uint256,string,uint256)`.\n mstore(0x00, 0x37aa7d4c)\n mstore(0x20, p0)\n mstore(0x40, 0x60)\n mstore(0x60, p2)\n writeString(0x80, p1)\n }\n _sendLogPayload(0x1c, 0xa4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n }\n }\n\n function log(uint256 p0, bytes32 p1, bytes32 p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n // Selector of `log(uint256,string,string)`.\n mstore(0x00, 0xb115611f)\n mstore(0x20, p0)\n mstore(0x40, 0x60)\n mstore(0x60, 0xa0)\n writeString(0x80, p1)\n writeString(0xc0, p2)\n }\n _sendLogPayload(0x1c, 0xe4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n }\n }\n\n function log(bytes32 p0, address p1, address p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n // Selector of `log(string,address,address)`.\n mstore(0x00, 0xfcec75e0)\n mstore(0x20, 0x60)\n mstore(0x40, p1)\n mstore(0x60, p2)\n writeString(0x80, p0)\n }\n _sendLogPayload(0x1c, 0xa4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n }\n }\n\n function log(bytes32 p0, address p1, bool p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n // Selector of `log(string,address,bool)`.\n mstore(0x00, 0xc91d5ed4)\n mstore(0x20, 0x60)\n mstore(0x40, p1)\n mstore(0x60, p2)\n writeString(0x80, p0)\n }\n _sendLogPayload(0x1c, 0xa4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n }\n }\n\n function log(bytes32 p0, address p1, uint256 p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n // Selector of `log(string,address,uint256)`.\n mstore(0x00, 0x0d26b925)\n mstore(0x20, 0x60)\n mstore(0x40, p1)\n mstore(0x60, p2)\n writeString(0x80, p0)\n }\n _sendLogPayload(0x1c, 0xa4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n }\n }\n\n function log(bytes32 p0, address p1, bytes32 p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n // Selector of `log(string,address,string)`.\n mstore(0x00, 0xe0e9ad4f)\n mstore(0x20, 0x60)\n mstore(0x40, p1)\n mstore(0x60, 0xa0)\n writeString(0x80, p0)\n writeString(0xc0, p2)\n }\n _sendLogPayload(0x1c, 0xe4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n }\n }\n\n function log(bytes32 p0, bool p1, address p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n // Selector of `log(string,bool,address)`.\n mstore(0x00, 0x932bbb38)\n mstore(0x20, 0x60)\n mstore(0x40, p1)\n mstore(0x60, p2)\n writeString(0x80, p0)\n }\n _sendLogPayload(0x1c, 0xa4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n }\n }\n\n function log(bytes32 p0, bool p1, bool p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n // Selector of `log(string,bool,bool)`.\n mstore(0x00, 0x850b7ad6)\n mstore(0x20, 0x60)\n mstore(0x40, p1)\n mstore(0x60, p2)\n writeString(0x80, p0)\n }\n _sendLogPayload(0x1c, 0xa4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n }\n }\n\n function log(bytes32 p0, bool p1, uint256 p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n // Selector of `log(string,bool,uint256)`.\n mstore(0x00, 0xc95958d6)\n mstore(0x20, 0x60)\n mstore(0x40, p1)\n mstore(0x60, p2)\n writeString(0x80, p0)\n }\n _sendLogPayload(0x1c, 0xa4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n }\n }\n\n function log(bytes32 p0, bool p1, bytes32 p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n // Selector of `log(string,bool,string)`.\n mstore(0x00, 0xe298f47d)\n mstore(0x20, 0x60)\n mstore(0x40, p1)\n mstore(0x60, 0xa0)\n writeString(0x80, p0)\n writeString(0xc0, p2)\n }\n _sendLogPayload(0x1c, 0xe4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n }\n }\n\n function log(bytes32 p0, uint256 p1, address p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n // Selector of `log(string,uint256,address)`.\n mstore(0x00, 0x1c7ec448)\n mstore(0x20, 0x60)\n mstore(0x40, p1)\n mstore(0x60, p2)\n writeString(0x80, p0)\n }\n _sendLogPayload(0x1c, 0xa4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n }\n }\n\n function log(bytes32 p0, uint256 p1, bool p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n // Selector of `log(string,uint256,bool)`.\n mstore(0x00, 0xca7733b1)\n mstore(0x20, 0x60)\n mstore(0x40, p1)\n mstore(0x60, p2)\n writeString(0x80, p0)\n }\n _sendLogPayload(0x1c, 0xa4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n }\n }\n\n function log(bytes32 p0, uint256 p1, uint256 p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n // Selector of `log(string,uint256,uint256)`.\n mstore(0x00, 0xca47c4eb)\n mstore(0x20, 0x60)\n mstore(0x40, p1)\n mstore(0x60, p2)\n writeString(0x80, p0)\n }\n _sendLogPayload(0x1c, 0xa4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n }\n }\n\n function log(bytes32 p0, uint256 p1, bytes32 p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n // Selector of `log(string,uint256,string)`.\n mstore(0x00, 0x5970e089)\n mstore(0x20, 0x60)\n mstore(0x40, p1)\n mstore(0x60, 0xa0)\n writeString(0x80, p0)\n writeString(0xc0, p2)\n }\n _sendLogPayload(0x1c, 0xe4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n }\n }\n\n function log(bytes32 p0, bytes32 p1, address p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n // Selector of `log(string,string,address)`.\n mstore(0x00, 0x95ed0195)\n mstore(0x20, 0x60)\n mstore(0x40, 0xa0)\n mstore(0x60, p2)\n writeString(0x80, p0)\n writeString(0xc0, p1)\n }\n _sendLogPayload(0x1c, 0xe4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n }\n }\n\n function log(bytes32 p0, bytes32 p1, bool p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n // Selector of `log(string,string,bool)`.\n mstore(0x00, 0xb0e0f9b5)\n mstore(0x20, 0x60)\n mstore(0x40, 0xa0)\n mstore(0x60, p2)\n writeString(0x80, p0)\n writeString(0xc0, p1)\n }\n _sendLogPayload(0x1c, 0xe4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n }\n }\n\n function log(bytes32 p0, bytes32 p1, uint256 p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n // Selector of `log(string,string,uint256)`.\n mstore(0x00, 0x5821efa1)\n mstore(0x20, 0x60)\n mstore(0x40, 0xa0)\n mstore(0x60, p2)\n writeString(0x80, p0)\n writeString(0xc0, p1)\n }\n _sendLogPayload(0x1c, 0xe4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n }\n }\n\n function log(bytes32 p0, bytes32 p1, bytes32 p2) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n bytes32 m9;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n m9 := mload(0x120)\n // Selector of `log(string,string,string)`.\n mstore(0x00, 0x2ced7cef)\n mstore(0x20, 0x60)\n mstore(0x40, 0xa0)\n mstore(0x60, 0xe0)\n writeString(0x80, p0)\n writeString(0xc0, p1)\n writeString(0x100, p2)\n }\n _sendLogPayload(0x1c, 0x124);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n mstore(0x120, m9)\n }\n }\n\n function log(address p0, address p1, address p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(address,address,address,address)`.\n mstore(0x00, 0x665bf134)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(address p0, address p1, address p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(address,address,address,bool)`.\n mstore(0x00, 0x0e378994)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(address p0, address p1, address p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(address,address,address,uint256)`.\n mstore(0x00, 0x94250d77)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(address p0, address p1, address p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(address,address,address,string)`.\n mstore(0x00, 0xf808da20)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, 0x80)\n writeString(0xa0, p3)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(address p0, address p1, bool p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(address,address,bool,address)`.\n mstore(0x00, 0x9f1bc36e)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(address p0, address p1, bool p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(address,address,bool,bool)`.\n mstore(0x00, 0x2cd4134a)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(address p0, address p1, bool p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(address,address,bool,uint256)`.\n mstore(0x00, 0x3971e78c)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(address p0, address p1, bool p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(address,address,bool,string)`.\n mstore(0x00, 0xaa6540c8)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, 0x80)\n writeString(0xa0, p3)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(address p0, address p1, uint256 p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(address,address,uint256,address)`.\n mstore(0x00, 0x8da6def5)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(address p0, address p1, uint256 p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(address,address,uint256,bool)`.\n mstore(0x00, 0x9b4254e2)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(address p0, address p1, uint256 p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(address,address,uint256,uint256)`.\n mstore(0x00, 0xbe553481)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(address p0, address p1, uint256 p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(address,address,uint256,string)`.\n mstore(0x00, 0xfdb4f990)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, 0x80)\n writeString(0xa0, p3)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(address p0, address p1, bytes32 p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(address,address,string,address)`.\n mstore(0x00, 0x8f736d16)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, 0x80)\n mstore(0x80, p3)\n writeString(0xa0, p2)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(address p0, address p1, bytes32 p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(address,address,string,bool)`.\n mstore(0x00, 0x6f1a594e)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, 0x80)\n mstore(0x80, p3)\n writeString(0xa0, p2)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(address p0, address p1, bytes32 p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(address,address,string,uint256)`.\n mstore(0x00, 0xef1cefe7)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, 0x80)\n mstore(0x80, p3)\n writeString(0xa0, p2)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(address p0, address p1, bytes32 p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n // Selector of `log(address,address,string,string)`.\n mstore(0x00, 0x21bdaf25)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, 0x80)\n mstore(0x80, 0xc0)\n writeString(0xa0, p2)\n writeString(0xe0, p3)\n }\n _sendLogPayload(0x1c, 0x104);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n }\n }\n\n function log(address p0, bool p1, address p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(address,bool,address,address)`.\n mstore(0x00, 0x660375dd)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(address p0, bool p1, address p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(address,bool,address,bool)`.\n mstore(0x00, 0xa6f50b0f)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(address p0, bool p1, address p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(address,bool,address,uint256)`.\n mstore(0x00, 0xa75c59de)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(address p0, bool p1, address p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(address,bool,address,string)`.\n mstore(0x00, 0x2dd778e6)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, 0x80)\n writeString(0xa0, p3)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(address p0, bool p1, bool p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(address,bool,bool,address)`.\n mstore(0x00, 0xcf394485)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(address p0, bool p1, bool p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(address,bool,bool,bool)`.\n mstore(0x00, 0xcac43479)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(address p0, bool p1, bool p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(address,bool,bool,uint256)`.\n mstore(0x00, 0x8c4e5de6)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(address p0, bool p1, bool p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(address,bool,bool,string)`.\n mstore(0x00, 0xdfc4a2e8)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, 0x80)\n writeString(0xa0, p3)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(address p0, bool p1, uint256 p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(address,bool,uint256,address)`.\n mstore(0x00, 0xccf790a1)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(address p0, bool p1, uint256 p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(address,bool,uint256,bool)`.\n mstore(0x00, 0xc4643e20)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(address p0, bool p1, uint256 p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(address,bool,uint256,uint256)`.\n mstore(0x00, 0x386ff5f4)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(address p0, bool p1, uint256 p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(address,bool,uint256,string)`.\n mstore(0x00, 0x0aa6cfad)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, 0x80)\n writeString(0xa0, p3)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(address p0, bool p1, bytes32 p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(address,bool,string,address)`.\n mstore(0x00, 0x19fd4956)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, 0x80)\n mstore(0x80, p3)\n writeString(0xa0, p2)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(address p0, bool p1, bytes32 p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(address,bool,string,bool)`.\n mstore(0x00, 0x50ad461d)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, 0x80)\n mstore(0x80, p3)\n writeString(0xa0, p2)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(address p0, bool p1, bytes32 p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(address,bool,string,uint256)`.\n mstore(0x00, 0x80e6a20b)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, 0x80)\n mstore(0x80, p3)\n writeString(0xa0, p2)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(address p0, bool p1, bytes32 p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n // Selector of `log(address,bool,string,string)`.\n mstore(0x00, 0x475c5c33)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, 0x80)\n mstore(0x80, 0xc0)\n writeString(0xa0, p2)\n writeString(0xe0, p3)\n }\n _sendLogPayload(0x1c, 0x104);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n }\n }\n\n function log(address p0, uint256 p1, address p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(address,uint256,address,address)`.\n mstore(0x00, 0x478d1c62)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(address p0, uint256 p1, address p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(address,uint256,address,bool)`.\n mstore(0x00, 0xa1bcc9b3)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(address p0, uint256 p1, address p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(address,uint256,address,uint256)`.\n mstore(0x00, 0x100f650e)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(address p0, uint256 p1, address p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(address,uint256,address,string)`.\n mstore(0x00, 0x1da986ea)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, 0x80)\n writeString(0xa0, p3)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(address p0, uint256 p1, bool p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(address,uint256,bool,address)`.\n mstore(0x00, 0xa31bfdcc)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(address p0, uint256 p1, bool p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(address,uint256,bool,bool)`.\n mstore(0x00, 0x3bf5e537)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(address p0, uint256 p1, bool p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(address,uint256,bool,uint256)`.\n mstore(0x00, 0x22f6b999)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(address p0, uint256 p1, bool p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(address,uint256,bool,string)`.\n mstore(0x00, 0xc5ad85f9)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, 0x80)\n writeString(0xa0, p3)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(address p0, uint256 p1, uint256 p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(address,uint256,uint256,address)`.\n mstore(0x00, 0x20e3984d)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(address p0, uint256 p1, uint256 p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(address,uint256,uint256,bool)`.\n mstore(0x00, 0x66f1bc67)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(address p0, uint256 p1, uint256 p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(address,uint256,uint256,uint256)`.\n mstore(0x00, 0x34f0e636)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(address p0, uint256 p1, uint256 p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(address,uint256,uint256,string)`.\n mstore(0x00, 0x4a28c017)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, 0x80)\n writeString(0xa0, p3)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(address p0, uint256 p1, bytes32 p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(address,uint256,string,address)`.\n mstore(0x00, 0x5c430d47)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, 0x80)\n mstore(0x80, p3)\n writeString(0xa0, p2)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(address p0, uint256 p1, bytes32 p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(address,uint256,string,bool)`.\n mstore(0x00, 0xcf18105c)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, 0x80)\n mstore(0x80, p3)\n writeString(0xa0, p2)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(address p0, uint256 p1, bytes32 p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(address,uint256,string,uint256)`.\n mstore(0x00, 0xbf01f891)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, 0x80)\n mstore(0x80, p3)\n writeString(0xa0, p2)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(address p0, uint256 p1, bytes32 p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n // Selector of `log(address,uint256,string,string)`.\n mstore(0x00, 0x88a8c406)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, 0x80)\n mstore(0x80, 0xc0)\n writeString(0xa0, p2)\n writeString(0xe0, p3)\n }\n _sendLogPayload(0x1c, 0x104);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n }\n }\n\n function log(address p0, bytes32 p1, address p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(address,string,address,address)`.\n mstore(0x00, 0x0d36fa20)\n mstore(0x20, p0)\n mstore(0x40, 0x80)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p1)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(address p0, bytes32 p1, address p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(address,string,address,bool)`.\n mstore(0x00, 0x0df12b76)\n mstore(0x20, p0)\n mstore(0x40, 0x80)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p1)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(address p0, bytes32 p1, address p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(address,string,address,uint256)`.\n mstore(0x00, 0x457fe3cf)\n mstore(0x20, p0)\n mstore(0x40, 0x80)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p1)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(address p0, bytes32 p1, address p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n // Selector of `log(address,string,address,string)`.\n mstore(0x00, 0xf7e36245)\n mstore(0x20, p0)\n mstore(0x40, 0x80)\n mstore(0x60, p2)\n mstore(0x80, 0xc0)\n writeString(0xa0, p1)\n writeString(0xe0, p3)\n }\n _sendLogPayload(0x1c, 0x104);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n }\n }\n\n function log(address p0, bytes32 p1, bool p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(address,string,bool,address)`.\n mstore(0x00, 0x205871c2)\n mstore(0x20, p0)\n mstore(0x40, 0x80)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p1)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(address p0, bytes32 p1, bool p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(address,string,bool,bool)`.\n mstore(0x00, 0x5f1d5c9f)\n mstore(0x20, p0)\n mstore(0x40, 0x80)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p1)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(address p0, bytes32 p1, bool p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(address,string,bool,uint256)`.\n mstore(0x00, 0x515e38b6)\n mstore(0x20, p0)\n mstore(0x40, 0x80)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p1)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(address p0, bytes32 p1, bool p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n // Selector of `log(address,string,bool,string)`.\n mstore(0x00, 0xbc0b61fe)\n mstore(0x20, p0)\n mstore(0x40, 0x80)\n mstore(0x60, p2)\n mstore(0x80, 0xc0)\n writeString(0xa0, p1)\n writeString(0xe0, p3)\n }\n _sendLogPayload(0x1c, 0x104);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n }\n }\n\n function log(address p0, bytes32 p1, uint256 p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(address,string,uint256,address)`.\n mstore(0x00, 0x63183678)\n mstore(0x20, p0)\n mstore(0x40, 0x80)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p1)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(address p0, bytes32 p1, uint256 p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(address,string,uint256,bool)`.\n mstore(0x00, 0x0ef7e050)\n mstore(0x20, p0)\n mstore(0x40, 0x80)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p1)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(address p0, bytes32 p1, uint256 p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(address,string,uint256,uint256)`.\n mstore(0x00, 0x1dc8e1b8)\n mstore(0x20, p0)\n mstore(0x40, 0x80)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p1)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(address p0, bytes32 p1, uint256 p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n // Selector of `log(address,string,uint256,string)`.\n mstore(0x00, 0x448830a8)\n mstore(0x20, p0)\n mstore(0x40, 0x80)\n mstore(0x60, p2)\n mstore(0x80, 0xc0)\n writeString(0xa0, p1)\n writeString(0xe0, p3)\n }\n _sendLogPayload(0x1c, 0x104);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n }\n }\n\n function log(address p0, bytes32 p1, bytes32 p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n // Selector of `log(address,string,string,address)`.\n mstore(0x00, 0xa04e2f87)\n mstore(0x20, p0)\n mstore(0x40, 0x80)\n mstore(0x60, 0xc0)\n mstore(0x80, p3)\n writeString(0xa0, p1)\n writeString(0xe0, p2)\n }\n _sendLogPayload(0x1c, 0x104);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n }\n }\n\n function log(address p0, bytes32 p1, bytes32 p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n // Selector of `log(address,string,string,bool)`.\n mstore(0x00, 0x35a5071f)\n mstore(0x20, p0)\n mstore(0x40, 0x80)\n mstore(0x60, 0xc0)\n mstore(0x80, p3)\n writeString(0xa0, p1)\n writeString(0xe0, p2)\n }\n _sendLogPayload(0x1c, 0x104);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n }\n }\n\n function log(address p0, bytes32 p1, bytes32 p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n // Selector of `log(address,string,string,uint256)`.\n mstore(0x00, 0x159f8927)\n mstore(0x20, p0)\n mstore(0x40, 0x80)\n mstore(0x60, 0xc0)\n mstore(0x80, p3)\n writeString(0xa0, p1)\n writeString(0xe0, p2)\n }\n _sendLogPayload(0x1c, 0x104);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n }\n }\n\n function log(address p0, bytes32 p1, bytes32 p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n bytes32 m9;\n bytes32 m10;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n m9 := mload(0x120)\n m10 := mload(0x140)\n // Selector of `log(address,string,string,string)`.\n mstore(0x00, 0x5d02c50b)\n mstore(0x20, p0)\n mstore(0x40, 0x80)\n mstore(0x60, 0xc0)\n mstore(0x80, 0x100)\n writeString(0xa0, p1)\n writeString(0xe0, p2)\n writeString(0x120, p3)\n }\n _sendLogPayload(0x1c, 0x144);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n mstore(0x120, m9)\n mstore(0x140, m10)\n }\n }\n\n function log(bool p0, address p1, address p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(bool,address,address,address)`.\n mstore(0x00, 0x1d14d001)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(bool p0, address p1, address p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(bool,address,address,bool)`.\n mstore(0x00, 0x46600be0)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(bool p0, address p1, address p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(bool,address,address,uint256)`.\n mstore(0x00, 0x0c66d1be)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(bool p0, address p1, address p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(bool,address,address,string)`.\n mstore(0x00, 0xd812a167)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, 0x80)\n writeString(0xa0, p3)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(bool p0, address p1, bool p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(bool,address,bool,address)`.\n mstore(0x00, 0x1c41a336)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(bool p0, address p1, bool p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(bool,address,bool,bool)`.\n mstore(0x00, 0x6a9c478b)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(bool p0, address p1, bool p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(bool,address,bool,uint256)`.\n mstore(0x00, 0x07831502)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(bool p0, address p1, bool p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(bool,address,bool,string)`.\n mstore(0x00, 0x4a66cb34)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, 0x80)\n writeString(0xa0, p3)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(bool p0, address p1, uint256 p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(bool,address,uint256,address)`.\n mstore(0x00, 0x136b05dd)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(bool p0, address p1, uint256 p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(bool,address,uint256,bool)`.\n mstore(0x00, 0xd6019f1c)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(bool p0, address p1, uint256 p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(bool,address,uint256,uint256)`.\n mstore(0x00, 0x7bf181a1)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(bool p0, address p1, uint256 p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(bool,address,uint256,string)`.\n mstore(0x00, 0x51f09ff8)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, 0x80)\n writeString(0xa0, p3)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(bool p0, address p1, bytes32 p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(bool,address,string,address)`.\n mstore(0x00, 0x6f7c603e)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, 0x80)\n mstore(0x80, p3)\n writeString(0xa0, p2)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(bool p0, address p1, bytes32 p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(bool,address,string,bool)`.\n mstore(0x00, 0xe2bfd60b)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, 0x80)\n mstore(0x80, p3)\n writeString(0xa0, p2)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(bool p0, address p1, bytes32 p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(bool,address,string,uint256)`.\n mstore(0x00, 0xc21f64c7)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, 0x80)\n mstore(0x80, p3)\n writeString(0xa0, p2)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(bool p0, address p1, bytes32 p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n // Selector of `log(bool,address,string,string)`.\n mstore(0x00, 0xa73c1db6)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, 0x80)\n mstore(0x80, 0xc0)\n writeString(0xa0, p2)\n writeString(0xe0, p3)\n }\n _sendLogPayload(0x1c, 0x104);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n }\n }\n\n function log(bool p0, bool p1, address p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(bool,bool,address,address)`.\n mstore(0x00, 0xf4880ea4)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(bool p0, bool p1, address p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(bool,bool,address,bool)`.\n mstore(0x00, 0xc0a302d8)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(bool p0, bool p1, address p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(bool,bool,address,uint256)`.\n mstore(0x00, 0x4c123d57)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(bool p0, bool p1, address p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(bool,bool,address,string)`.\n mstore(0x00, 0xa0a47963)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, 0x80)\n writeString(0xa0, p3)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(bool p0, bool p1, bool p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(bool,bool,bool,address)`.\n mstore(0x00, 0x8c329b1a)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(bool p0, bool p1, bool p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(bool,bool,bool,bool)`.\n mstore(0x00, 0x3b2a5ce0)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(bool p0, bool p1, bool p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(bool,bool,bool,uint256)`.\n mstore(0x00, 0x6d7045c1)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(bool p0, bool p1, bool p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(bool,bool,bool,string)`.\n mstore(0x00, 0x2ae408d4)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, 0x80)\n writeString(0xa0, p3)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(bool p0, bool p1, uint256 p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(bool,bool,uint256,address)`.\n mstore(0x00, 0x54a7a9a0)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(bool p0, bool p1, uint256 p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(bool,bool,uint256,bool)`.\n mstore(0x00, 0x619e4d0e)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(bool p0, bool p1, uint256 p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(bool,bool,uint256,uint256)`.\n mstore(0x00, 0x0bb00eab)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(bool p0, bool p1, uint256 p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(bool,bool,uint256,string)`.\n mstore(0x00, 0x7dd4d0e0)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, 0x80)\n writeString(0xa0, p3)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(bool p0, bool p1, bytes32 p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(bool,bool,string,address)`.\n mstore(0x00, 0xf9ad2b89)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, 0x80)\n mstore(0x80, p3)\n writeString(0xa0, p2)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(bool p0, bool p1, bytes32 p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(bool,bool,string,bool)`.\n mstore(0x00, 0xb857163a)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, 0x80)\n mstore(0x80, p3)\n writeString(0xa0, p2)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(bool p0, bool p1, bytes32 p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(bool,bool,string,uint256)`.\n mstore(0x00, 0xe3a9ca2f)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, 0x80)\n mstore(0x80, p3)\n writeString(0xa0, p2)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(bool p0, bool p1, bytes32 p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n // Selector of `log(bool,bool,string,string)`.\n mstore(0x00, 0x6d1e8751)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, 0x80)\n mstore(0x80, 0xc0)\n writeString(0xa0, p2)\n writeString(0xe0, p3)\n }\n _sendLogPayload(0x1c, 0x104);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n }\n }\n\n function log(bool p0, uint256 p1, address p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(bool,uint256,address,address)`.\n mstore(0x00, 0x26f560a8)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(bool p0, uint256 p1, address p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(bool,uint256,address,bool)`.\n mstore(0x00, 0xb4c314ff)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(bool p0, uint256 p1, address p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(bool,uint256,address,uint256)`.\n mstore(0x00, 0x1537dc87)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(bool p0, uint256 p1, address p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(bool,uint256,address,string)`.\n mstore(0x00, 0x1bb3b09a)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, 0x80)\n writeString(0xa0, p3)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(bool p0, uint256 p1, bool p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(bool,uint256,bool,address)`.\n mstore(0x00, 0x9acd3616)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(bool p0, uint256 p1, bool p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(bool,uint256,bool,bool)`.\n mstore(0x00, 0xceb5f4d7)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(bool p0, uint256 p1, bool p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(bool,uint256,bool,uint256)`.\n mstore(0x00, 0x7f9bbca2)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(bool p0, uint256 p1, bool p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(bool,uint256,bool,string)`.\n mstore(0x00, 0x9143dbb1)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, 0x80)\n writeString(0xa0, p3)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(bool p0, uint256 p1, uint256 p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(bool,uint256,uint256,address)`.\n mstore(0x00, 0x00dd87b9)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(bool p0, uint256 p1, uint256 p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(bool,uint256,uint256,bool)`.\n mstore(0x00, 0xbe984353)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(bool p0, uint256 p1, uint256 p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(bool,uint256,uint256,uint256)`.\n mstore(0x00, 0x374bb4b2)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(bool p0, uint256 p1, uint256 p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(bool,uint256,uint256,string)`.\n mstore(0x00, 0x8e69fb5d)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, 0x80)\n writeString(0xa0, p3)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(bool p0, uint256 p1, bytes32 p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(bool,uint256,string,address)`.\n mstore(0x00, 0xfedd1fff)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, 0x80)\n mstore(0x80, p3)\n writeString(0xa0, p2)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(bool p0, uint256 p1, bytes32 p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(bool,uint256,string,bool)`.\n mstore(0x00, 0xe5e70b2b)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, 0x80)\n mstore(0x80, p3)\n writeString(0xa0, p2)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(bool p0, uint256 p1, bytes32 p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(bool,uint256,string,uint256)`.\n mstore(0x00, 0x6a1199e2)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, 0x80)\n mstore(0x80, p3)\n writeString(0xa0, p2)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(bool p0, uint256 p1, bytes32 p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n // Selector of `log(bool,uint256,string,string)`.\n mstore(0x00, 0xf5bc2249)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, 0x80)\n mstore(0x80, 0xc0)\n writeString(0xa0, p2)\n writeString(0xe0, p3)\n }\n _sendLogPayload(0x1c, 0x104);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n }\n }\n\n function log(bool p0, bytes32 p1, address p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(bool,string,address,address)`.\n mstore(0x00, 0x2b2b18dc)\n mstore(0x20, p0)\n mstore(0x40, 0x80)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p1)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(bool p0, bytes32 p1, address p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(bool,string,address,bool)`.\n mstore(0x00, 0x6dd434ca)\n mstore(0x20, p0)\n mstore(0x40, 0x80)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p1)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(bool p0, bytes32 p1, address p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(bool,string,address,uint256)`.\n mstore(0x00, 0xa5cada94)\n mstore(0x20, p0)\n mstore(0x40, 0x80)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p1)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(bool p0, bytes32 p1, address p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n // Selector of `log(bool,string,address,string)`.\n mstore(0x00, 0x12d6c788)\n mstore(0x20, p0)\n mstore(0x40, 0x80)\n mstore(0x60, p2)\n mstore(0x80, 0xc0)\n writeString(0xa0, p1)\n writeString(0xe0, p3)\n }\n _sendLogPayload(0x1c, 0x104);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n }\n }\n\n function log(bool p0, bytes32 p1, bool p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(bool,string,bool,address)`.\n mstore(0x00, 0x538e06ab)\n mstore(0x20, p0)\n mstore(0x40, 0x80)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p1)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(bool p0, bytes32 p1, bool p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(bool,string,bool,bool)`.\n mstore(0x00, 0xdc5e935b)\n mstore(0x20, p0)\n mstore(0x40, 0x80)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p1)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(bool p0, bytes32 p1, bool p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(bool,string,bool,uint256)`.\n mstore(0x00, 0x1606a393)\n mstore(0x20, p0)\n mstore(0x40, 0x80)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p1)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(bool p0, bytes32 p1, bool p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n // Selector of `log(bool,string,bool,string)`.\n mstore(0x00, 0x483d0416)\n mstore(0x20, p0)\n mstore(0x40, 0x80)\n mstore(0x60, p2)\n mstore(0x80, 0xc0)\n writeString(0xa0, p1)\n writeString(0xe0, p3)\n }\n _sendLogPayload(0x1c, 0x104);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n }\n }\n\n function log(bool p0, bytes32 p1, uint256 p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(bool,string,uint256,address)`.\n mstore(0x00, 0x1596a1ce)\n mstore(0x20, p0)\n mstore(0x40, 0x80)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p1)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(bool p0, bytes32 p1, uint256 p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(bool,string,uint256,bool)`.\n mstore(0x00, 0x6b0e5d53)\n mstore(0x20, p0)\n mstore(0x40, 0x80)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p1)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(bool p0, bytes32 p1, uint256 p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(bool,string,uint256,uint256)`.\n mstore(0x00, 0x28863fcb)\n mstore(0x20, p0)\n mstore(0x40, 0x80)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p1)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(bool p0, bytes32 p1, uint256 p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n // Selector of `log(bool,string,uint256,string)`.\n mstore(0x00, 0x1ad96de6)\n mstore(0x20, p0)\n mstore(0x40, 0x80)\n mstore(0x60, p2)\n mstore(0x80, 0xc0)\n writeString(0xa0, p1)\n writeString(0xe0, p3)\n }\n _sendLogPayload(0x1c, 0x104);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n }\n }\n\n function log(bool p0, bytes32 p1, bytes32 p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n // Selector of `log(bool,string,string,address)`.\n mstore(0x00, 0x97d394d8)\n mstore(0x20, p0)\n mstore(0x40, 0x80)\n mstore(0x60, 0xc0)\n mstore(0x80, p3)\n writeString(0xa0, p1)\n writeString(0xe0, p2)\n }\n _sendLogPayload(0x1c, 0x104);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n }\n }\n\n function log(bool p0, bytes32 p1, bytes32 p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n // Selector of `log(bool,string,string,bool)`.\n mstore(0x00, 0x1e4b87e5)\n mstore(0x20, p0)\n mstore(0x40, 0x80)\n mstore(0x60, 0xc0)\n mstore(0x80, p3)\n writeString(0xa0, p1)\n writeString(0xe0, p2)\n }\n _sendLogPayload(0x1c, 0x104);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n }\n }\n\n function log(bool p0, bytes32 p1, bytes32 p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n // Selector of `log(bool,string,string,uint256)`.\n mstore(0x00, 0x7be0c3eb)\n mstore(0x20, p0)\n mstore(0x40, 0x80)\n mstore(0x60, 0xc0)\n mstore(0x80, p3)\n writeString(0xa0, p1)\n writeString(0xe0, p2)\n }\n _sendLogPayload(0x1c, 0x104);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n }\n }\n\n function log(bool p0, bytes32 p1, bytes32 p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n bytes32 m9;\n bytes32 m10;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n m9 := mload(0x120)\n m10 := mload(0x140)\n // Selector of `log(bool,string,string,string)`.\n mstore(0x00, 0x1762e32a)\n mstore(0x20, p0)\n mstore(0x40, 0x80)\n mstore(0x60, 0xc0)\n mstore(0x80, 0x100)\n writeString(0xa0, p1)\n writeString(0xe0, p2)\n writeString(0x120, p3)\n }\n _sendLogPayload(0x1c, 0x144);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n mstore(0x120, m9)\n mstore(0x140, m10)\n }\n }\n\n function log(uint256 p0, address p1, address p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(uint256,address,address,address)`.\n mstore(0x00, 0x2488b414)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(uint256 p0, address p1, address p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(uint256,address,address,bool)`.\n mstore(0x00, 0x091ffaf5)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(uint256 p0, address p1, address p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(uint256,address,address,uint256)`.\n mstore(0x00, 0x736efbb6)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(uint256 p0, address p1, address p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(uint256,address,address,string)`.\n mstore(0x00, 0x031c6f73)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, 0x80)\n writeString(0xa0, p3)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(uint256 p0, address p1, bool p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(uint256,address,bool,address)`.\n mstore(0x00, 0xef72c513)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(uint256 p0, address p1, bool p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(uint256,address,bool,bool)`.\n mstore(0x00, 0xe351140f)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(uint256 p0, address p1, bool p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(uint256,address,bool,uint256)`.\n mstore(0x00, 0x5abd992a)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(uint256 p0, address p1, bool p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(uint256,address,bool,string)`.\n mstore(0x00, 0x90fb06aa)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, 0x80)\n writeString(0xa0, p3)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(uint256 p0, address p1, uint256 p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(uint256,address,uint256,address)`.\n mstore(0x00, 0x15c127b5)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(uint256 p0, address p1, uint256 p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(uint256,address,uint256,bool)`.\n mstore(0x00, 0x5f743a7c)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(uint256 p0, address p1, uint256 p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(uint256,address,uint256,uint256)`.\n mstore(0x00, 0x0c9cd9c1)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(uint256 p0, address p1, uint256 p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(uint256,address,uint256,string)`.\n mstore(0x00, 0xddb06521)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, 0x80)\n writeString(0xa0, p3)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(uint256 p0, address p1, bytes32 p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(uint256,address,string,address)`.\n mstore(0x00, 0x9cba8fff)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, 0x80)\n mstore(0x80, p3)\n writeString(0xa0, p2)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(uint256 p0, address p1, bytes32 p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(uint256,address,string,bool)`.\n mstore(0x00, 0xcc32ab07)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, 0x80)\n mstore(0x80, p3)\n writeString(0xa0, p2)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(uint256 p0, address p1, bytes32 p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(uint256,address,string,uint256)`.\n mstore(0x00, 0x46826b5d)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, 0x80)\n mstore(0x80, p3)\n writeString(0xa0, p2)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(uint256 p0, address p1, bytes32 p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n // Selector of `log(uint256,address,string,string)`.\n mstore(0x00, 0x3e128ca3)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, 0x80)\n mstore(0x80, 0xc0)\n writeString(0xa0, p2)\n writeString(0xe0, p3)\n }\n _sendLogPayload(0x1c, 0x104);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n }\n }\n\n function log(uint256 p0, bool p1, address p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(uint256,bool,address,address)`.\n mstore(0x00, 0xa1ef4cbb)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(uint256 p0, bool p1, address p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(uint256,bool,address,bool)`.\n mstore(0x00, 0x454d54a5)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(uint256 p0, bool p1, address p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(uint256,bool,address,uint256)`.\n mstore(0x00, 0x078287f5)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(uint256 p0, bool p1, address p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(uint256,bool,address,string)`.\n mstore(0x00, 0xade052c7)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, 0x80)\n writeString(0xa0, p3)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(uint256 p0, bool p1, bool p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(uint256,bool,bool,address)`.\n mstore(0x00, 0x69640b59)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(uint256 p0, bool p1, bool p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(uint256,bool,bool,bool)`.\n mstore(0x00, 0xb6f577a1)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(uint256 p0, bool p1, bool p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(uint256,bool,bool,uint256)`.\n mstore(0x00, 0x7464ce23)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(uint256 p0, bool p1, bool p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(uint256,bool,bool,string)`.\n mstore(0x00, 0xdddb9561)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, 0x80)\n writeString(0xa0, p3)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(uint256 p0, bool p1, uint256 p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(uint256,bool,uint256,address)`.\n mstore(0x00, 0x88cb6041)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(uint256 p0, bool p1, uint256 p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(uint256,bool,uint256,bool)`.\n mstore(0x00, 0x91a02e2a)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(uint256 p0, bool p1, uint256 p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(uint256,bool,uint256,uint256)`.\n mstore(0x00, 0xc6acc7a8)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(uint256 p0, bool p1, uint256 p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(uint256,bool,uint256,string)`.\n mstore(0x00, 0xde03e774)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, 0x80)\n writeString(0xa0, p3)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(uint256 p0, bool p1, bytes32 p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(uint256,bool,string,address)`.\n mstore(0x00, 0xef529018)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, 0x80)\n mstore(0x80, p3)\n writeString(0xa0, p2)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(uint256 p0, bool p1, bytes32 p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(uint256,bool,string,bool)`.\n mstore(0x00, 0xeb928d7f)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, 0x80)\n mstore(0x80, p3)\n writeString(0xa0, p2)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(uint256 p0, bool p1, bytes32 p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(uint256,bool,string,uint256)`.\n mstore(0x00, 0x2c1d0746)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, 0x80)\n mstore(0x80, p3)\n writeString(0xa0, p2)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(uint256 p0, bool p1, bytes32 p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n // Selector of `log(uint256,bool,string,string)`.\n mstore(0x00, 0x68c8b8bd)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, 0x80)\n mstore(0x80, 0xc0)\n writeString(0xa0, p2)\n writeString(0xe0, p3)\n }\n _sendLogPayload(0x1c, 0x104);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n }\n }\n\n function log(uint256 p0, uint256 p1, address p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(uint256,uint256,address,address)`.\n mstore(0x00, 0x56a5d1b1)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(uint256 p0, uint256 p1, address p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(uint256,uint256,address,bool)`.\n mstore(0x00, 0x15cac476)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(uint256 p0, uint256 p1, address p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(uint256,uint256,address,uint256)`.\n mstore(0x00, 0x88f6e4b2)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(uint256 p0, uint256 p1, address p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(uint256,uint256,address,string)`.\n mstore(0x00, 0x6cde40b8)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, 0x80)\n writeString(0xa0, p3)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(uint256 p0, uint256 p1, bool p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(uint256,uint256,bool,address)`.\n mstore(0x00, 0x9a816a83)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(uint256 p0, uint256 p1, bool p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(uint256,uint256,bool,bool)`.\n mstore(0x00, 0xab085ae6)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(uint256 p0, uint256 p1, bool p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(uint256,uint256,bool,uint256)`.\n mstore(0x00, 0xeb7f6fd2)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(uint256 p0, uint256 p1, bool p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(uint256,uint256,bool,string)`.\n mstore(0x00, 0xa5b4fc99)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, 0x80)\n writeString(0xa0, p3)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(uint256 p0, uint256 p1, uint256 p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(uint256,uint256,uint256,address)`.\n mstore(0x00, 0xfa8185af)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(uint256 p0, uint256 p1, uint256 p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(uint256,uint256,uint256,bool)`.\n mstore(0x00, 0xc598d185)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(uint256 p0, uint256 p1, uint256 p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n /// @solidity memory-safe-assembly\n assembly {\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n // Selector of `log(uint256,uint256,uint256,uint256)`.\n mstore(0x00, 0x193fb800)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n }\n _sendLogPayload(0x1c, 0x84);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n }\n }\n\n function log(uint256 p0, uint256 p1, uint256 p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(uint256,uint256,uint256,string)`.\n mstore(0x00, 0x59cfcbe3)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, 0x80)\n writeString(0xa0, p3)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(uint256 p0, uint256 p1, bytes32 p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(uint256,uint256,string,address)`.\n mstore(0x00, 0x42d21db7)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, 0x80)\n mstore(0x80, p3)\n writeString(0xa0, p2)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(uint256 p0, uint256 p1, bytes32 p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(uint256,uint256,string,bool)`.\n mstore(0x00, 0x7af6ab25)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, 0x80)\n mstore(0x80, p3)\n writeString(0xa0, p2)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(uint256 p0, uint256 p1, bytes32 p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(uint256,uint256,string,uint256)`.\n mstore(0x00, 0x5da297eb)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, 0x80)\n mstore(0x80, p3)\n writeString(0xa0, p2)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(uint256 p0, uint256 p1, bytes32 p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n // Selector of `log(uint256,uint256,string,string)`.\n mstore(0x00, 0x27d8afd2)\n mstore(0x20, p0)\n mstore(0x40, p1)\n mstore(0x60, 0x80)\n mstore(0x80, 0xc0)\n writeString(0xa0, p2)\n writeString(0xe0, p3)\n }\n _sendLogPayload(0x1c, 0x104);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n }\n }\n\n function log(uint256 p0, bytes32 p1, address p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(uint256,string,address,address)`.\n mstore(0x00, 0x6168ed61)\n mstore(0x20, p0)\n mstore(0x40, 0x80)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p1)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(uint256 p0, bytes32 p1, address p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(uint256,string,address,bool)`.\n mstore(0x00, 0x90c30a56)\n mstore(0x20, p0)\n mstore(0x40, 0x80)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p1)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(uint256 p0, bytes32 p1, address p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(uint256,string,address,uint256)`.\n mstore(0x00, 0xe8d3018d)\n mstore(0x20, p0)\n mstore(0x40, 0x80)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p1)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(uint256 p0, bytes32 p1, address p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n // Selector of `log(uint256,string,address,string)`.\n mstore(0x00, 0x9c3adfa1)\n mstore(0x20, p0)\n mstore(0x40, 0x80)\n mstore(0x60, p2)\n mstore(0x80, 0xc0)\n writeString(0xa0, p1)\n writeString(0xe0, p3)\n }\n _sendLogPayload(0x1c, 0x104);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n }\n }\n\n function log(uint256 p0, bytes32 p1, bool p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(uint256,string,bool,address)`.\n mstore(0x00, 0xae2ec581)\n mstore(0x20, p0)\n mstore(0x40, 0x80)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p1)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(uint256 p0, bytes32 p1, bool p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(uint256,string,bool,bool)`.\n mstore(0x00, 0xba535d9c)\n mstore(0x20, p0)\n mstore(0x40, 0x80)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p1)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(uint256 p0, bytes32 p1, bool p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(uint256,string,bool,uint256)`.\n mstore(0x00, 0xcf009880)\n mstore(0x20, p0)\n mstore(0x40, 0x80)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p1)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(uint256 p0, bytes32 p1, bool p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n // Selector of `log(uint256,string,bool,string)`.\n mstore(0x00, 0xd2d423cd)\n mstore(0x20, p0)\n mstore(0x40, 0x80)\n mstore(0x60, p2)\n mstore(0x80, 0xc0)\n writeString(0xa0, p1)\n writeString(0xe0, p3)\n }\n _sendLogPayload(0x1c, 0x104);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n }\n }\n\n function log(uint256 p0, bytes32 p1, uint256 p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(uint256,string,uint256,address)`.\n mstore(0x00, 0x3b2279b4)\n mstore(0x20, p0)\n mstore(0x40, 0x80)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p1)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(uint256 p0, bytes32 p1, uint256 p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(uint256,string,uint256,bool)`.\n mstore(0x00, 0x691a8f74)\n mstore(0x20, p0)\n mstore(0x40, 0x80)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p1)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(uint256 p0, bytes32 p1, uint256 p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(uint256,string,uint256,uint256)`.\n mstore(0x00, 0x82c25b74)\n mstore(0x20, p0)\n mstore(0x40, 0x80)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p1)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(uint256 p0, bytes32 p1, uint256 p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n // Selector of `log(uint256,string,uint256,string)`.\n mstore(0x00, 0xb7b914ca)\n mstore(0x20, p0)\n mstore(0x40, 0x80)\n mstore(0x60, p2)\n mstore(0x80, 0xc0)\n writeString(0xa0, p1)\n writeString(0xe0, p3)\n }\n _sendLogPayload(0x1c, 0x104);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n }\n }\n\n function log(uint256 p0, bytes32 p1, bytes32 p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n // Selector of `log(uint256,string,string,address)`.\n mstore(0x00, 0xd583c602)\n mstore(0x20, p0)\n mstore(0x40, 0x80)\n mstore(0x60, 0xc0)\n mstore(0x80, p3)\n writeString(0xa0, p1)\n writeString(0xe0, p2)\n }\n _sendLogPayload(0x1c, 0x104);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n }\n }\n\n function log(uint256 p0, bytes32 p1, bytes32 p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n // Selector of `log(uint256,string,string,bool)`.\n mstore(0x00, 0xb3a6b6bd)\n mstore(0x20, p0)\n mstore(0x40, 0x80)\n mstore(0x60, 0xc0)\n mstore(0x80, p3)\n writeString(0xa0, p1)\n writeString(0xe0, p2)\n }\n _sendLogPayload(0x1c, 0x104);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n }\n }\n\n function log(uint256 p0, bytes32 p1, bytes32 p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n // Selector of `log(uint256,string,string,uint256)`.\n mstore(0x00, 0xb028c9bd)\n mstore(0x20, p0)\n mstore(0x40, 0x80)\n mstore(0x60, 0xc0)\n mstore(0x80, p3)\n writeString(0xa0, p1)\n writeString(0xe0, p2)\n }\n _sendLogPayload(0x1c, 0x104);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n }\n }\n\n function log(uint256 p0, bytes32 p1, bytes32 p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n bytes32 m9;\n bytes32 m10;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n m9 := mload(0x120)\n m10 := mload(0x140)\n // Selector of `log(uint256,string,string,string)`.\n mstore(0x00, 0x21ad0683)\n mstore(0x20, p0)\n mstore(0x40, 0x80)\n mstore(0x60, 0xc0)\n mstore(0x80, 0x100)\n writeString(0xa0, p1)\n writeString(0xe0, p2)\n writeString(0x120, p3)\n }\n _sendLogPayload(0x1c, 0x144);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n mstore(0x120, m9)\n mstore(0x140, m10)\n }\n }\n\n function log(bytes32 p0, address p1, address p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(string,address,address,address)`.\n mstore(0x00, 0xed8f28f6)\n mstore(0x20, 0x80)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p0)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(bytes32 p0, address p1, address p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(string,address,address,bool)`.\n mstore(0x00, 0xb59dbd60)\n mstore(0x20, 0x80)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p0)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(bytes32 p0, address p1, address p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(string,address,address,uint256)`.\n mstore(0x00, 0x8ef3f399)\n mstore(0x20, 0x80)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p0)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(bytes32 p0, address p1, address p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n // Selector of `log(string,address,address,string)`.\n mstore(0x00, 0x800a1c67)\n mstore(0x20, 0x80)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, 0xc0)\n writeString(0xa0, p0)\n writeString(0xe0, p3)\n }\n _sendLogPayload(0x1c, 0x104);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n }\n }\n\n function log(bytes32 p0, address p1, bool p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(string,address,bool,address)`.\n mstore(0x00, 0x223603bd)\n mstore(0x20, 0x80)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p0)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(bytes32 p0, address p1, bool p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(string,address,bool,bool)`.\n mstore(0x00, 0x79884c2b)\n mstore(0x20, 0x80)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p0)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(bytes32 p0, address p1, bool p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(string,address,bool,uint256)`.\n mstore(0x00, 0x3e9f866a)\n mstore(0x20, 0x80)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p0)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(bytes32 p0, address p1, bool p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n // Selector of `log(string,address,bool,string)`.\n mstore(0x00, 0x0454c079)\n mstore(0x20, 0x80)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, 0xc0)\n writeString(0xa0, p0)\n writeString(0xe0, p3)\n }\n _sendLogPayload(0x1c, 0x104);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n }\n }\n\n function log(bytes32 p0, address p1, uint256 p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(string,address,uint256,address)`.\n mstore(0x00, 0x63fb8bc5)\n mstore(0x20, 0x80)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p0)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(bytes32 p0, address p1, uint256 p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(string,address,uint256,bool)`.\n mstore(0x00, 0xfc4845f0)\n mstore(0x20, 0x80)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p0)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(bytes32 p0, address p1, uint256 p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(string,address,uint256,uint256)`.\n mstore(0x00, 0xf8f51b1e)\n mstore(0x20, 0x80)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p0)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(bytes32 p0, address p1, uint256 p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n // Selector of `log(string,address,uint256,string)`.\n mstore(0x00, 0x5a477632)\n mstore(0x20, 0x80)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, 0xc0)\n writeString(0xa0, p0)\n writeString(0xe0, p3)\n }\n _sendLogPayload(0x1c, 0x104);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n }\n }\n\n function log(bytes32 p0, address p1, bytes32 p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n // Selector of `log(string,address,string,address)`.\n mstore(0x00, 0xaabc9a31)\n mstore(0x20, 0x80)\n mstore(0x40, p1)\n mstore(0x60, 0xc0)\n mstore(0x80, p3)\n writeString(0xa0, p0)\n writeString(0xe0, p2)\n }\n _sendLogPayload(0x1c, 0x104);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n }\n }\n\n function log(bytes32 p0, address p1, bytes32 p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n // Selector of `log(string,address,string,bool)`.\n mstore(0x00, 0x5f15d28c)\n mstore(0x20, 0x80)\n mstore(0x40, p1)\n mstore(0x60, 0xc0)\n mstore(0x80, p3)\n writeString(0xa0, p0)\n writeString(0xe0, p2)\n }\n _sendLogPayload(0x1c, 0x104);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n }\n }\n\n function log(bytes32 p0, address p1, bytes32 p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n // Selector of `log(string,address,string,uint256)`.\n mstore(0x00, 0x91d1112e)\n mstore(0x20, 0x80)\n mstore(0x40, p1)\n mstore(0x60, 0xc0)\n mstore(0x80, p3)\n writeString(0xa0, p0)\n writeString(0xe0, p2)\n }\n _sendLogPayload(0x1c, 0x104);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n }\n }\n\n function log(bytes32 p0, address p1, bytes32 p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n bytes32 m9;\n bytes32 m10;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n m9 := mload(0x120)\n m10 := mload(0x140)\n // Selector of `log(string,address,string,string)`.\n mstore(0x00, 0x245986f2)\n mstore(0x20, 0x80)\n mstore(0x40, p1)\n mstore(0x60, 0xc0)\n mstore(0x80, 0x100)\n writeString(0xa0, p0)\n writeString(0xe0, p2)\n writeString(0x120, p3)\n }\n _sendLogPayload(0x1c, 0x144);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n mstore(0x120, m9)\n mstore(0x140, m10)\n }\n }\n\n function log(bytes32 p0, bool p1, address p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(string,bool,address,address)`.\n mstore(0x00, 0x33e9dd1d)\n mstore(0x20, 0x80)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p0)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(bytes32 p0, bool p1, address p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(string,bool,address,bool)`.\n mstore(0x00, 0x958c28c6)\n mstore(0x20, 0x80)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p0)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(bytes32 p0, bool p1, address p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(string,bool,address,uint256)`.\n mstore(0x00, 0x5d08bb05)\n mstore(0x20, 0x80)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p0)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(bytes32 p0, bool p1, address p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n // Selector of `log(string,bool,address,string)`.\n mstore(0x00, 0x2d8e33a4)\n mstore(0x20, 0x80)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, 0xc0)\n writeString(0xa0, p0)\n writeString(0xe0, p3)\n }\n _sendLogPayload(0x1c, 0x104);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n }\n }\n\n function log(bytes32 p0, bool p1, bool p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(string,bool,bool,address)`.\n mstore(0x00, 0x7190a529)\n mstore(0x20, 0x80)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p0)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(bytes32 p0, bool p1, bool p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(string,bool,bool,bool)`.\n mstore(0x00, 0x895af8c5)\n mstore(0x20, 0x80)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p0)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(bytes32 p0, bool p1, bool p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(string,bool,bool,uint256)`.\n mstore(0x00, 0x8e3f78a9)\n mstore(0x20, 0x80)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p0)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(bytes32 p0, bool p1, bool p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n // Selector of `log(string,bool,bool,string)`.\n mstore(0x00, 0x9d22d5dd)\n mstore(0x20, 0x80)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, 0xc0)\n writeString(0xa0, p0)\n writeString(0xe0, p3)\n }\n _sendLogPayload(0x1c, 0x104);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n }\n }\n\n function log(bytes32 p0, bool p1, uint256 p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(string,bool,uint256,address)`.\n mstore(0x00, 0x935e09bf)\n mstore(0x20, 0x80)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p0)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(bytes32 p0, bool p1, uint256 p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(string,bool,uint256,bool)`.\n mstore(0x00, 0x8af7cf8a)\n mstore(0x20, 0x80)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p0)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(bytes32 p0, bool p1, uint256 p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(string,bool,uint256,uint256)`.\n mstore(0x00, 0x64b5bb67)\n mstore(0x20, 0x80)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p0)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(bytes32 p0, bool p1, uint256 p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n // Selector of `log(string,bool,uint256,string)`.\n mstore(0x00, 0x742d6ee7)\n mstore(0x20, 0x80)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, 0xc0)\n writeString(0xa0, p0)\n writeString(0xe0, p3)\n }\n _sendLogPayload(0x1c, 0x104);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n }\n }\n\n function log(bytes32 p0, bool p1, bytes32 p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n // Selector of `log(string,bool,string,address)`.\n mstore(0x00, 0xe0625b29)\n mstore(0x20, 0x80)\n mstore(0x40, p1)\n mstore(0x60, 0xc0)\n mstore(0x80, p3)\n writeString(0xa0, p0)\n writeString(0xe0, p2)\n }\n _sendLogPayload(0x1c, 0x104);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n }\n }\n\n function log(bytes32 p0, bool p1, bytes32 p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n // Selector of `log(string,bool,string,bool)`.\n mstore(0x00, 0x3f8a701d)\n mstore(0x20, 0x80)\n mstore(0x40, p1)\n mstore(0x60, 0xc0)\n mstore(0x80, p3)\n writeString(0xa0, p0)\n writeString(0xe0, p2)\n }\n _sendLogPayload(0x1c, 0x104);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n }\n }\n\n function log(bytes32 p0, bool p1, bytes32 p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n // Selector of `log(string,bool,string,uint256)`.\n mstore(0x00, 0x24f91465)\n mstore(0x20, 0x80)\n mstore(0x40, p1)\n mstore(0x60, 0xc0)\n mstore(0x80, p3)\n writeString(0xa0, p0)\n writeString(0xe0, p2)\n }\n _sendLogPayload(0x1c, 0x104);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n }\n }\n\n function log(bytes32 p0, bool p1, bytes32 p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n bytes32 m9;\n bytes32 m10;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n m9 := mload(0x120)\n m10 := mload(0x140)\n // Selector of `log(string,bool,string,string)`.\n mstore(0x00, 0xa826caeb)\n mstore(0x20, 0x80)\n mstore(0x40, p1)\n mstore(0x60, 0xc0)\n mstore(0x80, 0x100)\n writeString(0xa0, p0)\n writeString(0xe0, p2)\n writeString(0x120, p3)\n }\n _sendLogPayload(0x1c, 0x144);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n mstore(0x120, m9)\n mstore(0x140, m10)\n }\n }\n\n function log(bytes32 p0, uint256 p1, address p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(string,uint256,address,address)`.\n mstore(0x00, 0x5ea2b7ae)\n mstore(0x20, 0x80)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p0)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(bytes32 p0, uint256 p1, address p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(string,uint256,address,bool)`.\n mstore(0x00, 0x82112a42)\n mstore(0x20, 0x80)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p0)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(bytes32 p0, uint256 p1, address p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(string,uint256,address,uint256)`.\n mstore(0x00, 0x4f04fdc6)\n mstore(0x20, 0x80)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p0)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(bytes32 p0, uint256 p1, address p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n // Selector of `log(string,uint256,address,string)`.\n mstore(0x00, 0x9ffb2f93)\n mstore(0x20, 0x80)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, 0xc0)\n writeString(0xa0, p0)\n writeString(0xe0, p3)\n }\n _sendLogPayload(0x1c, 0x104);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n }\n }\n\n function log(bytes32 p0, uint256 p1, bool p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(string,uint256,bool,address)`.\n mstore(0x00, 0xe0e95b98)\n mstore(0x20, 0x80)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p0)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(bytes32 p0, uint256 p1, bool p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(string,uint256,bool,bool)`.\n mstore(0x00, 0x354c36d6)\n mstore(0x20, 0x80)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p0)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(bytes32 p0, uint256 p1, bool p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(string,uint256,bool,uint256)`.\n mstore(0x00, 0xe41b6f6f)\n mstore(0x20, 0x80)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p0)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(bytes32 p0, uint256 p1, bool p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n // Selector of `log(string,uint256,bool,string)`.\n mstore(0x00, 0xabf73a98)\n mstore(0x20, 0x80)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, 0xc0)\n writeString(0xa0, p0)\n writeString(0xe0, p3)\n }\n _sendLogPayload(0x1c, 0x104);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n }\n }\n\n function log(bytes32 p0, uint256 p1, uint256 p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(string,uint256,uint256,address)`.\n mstore(0x00, 0xe21de278)\n mstore(0x20, 0x80)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p0)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(bytes32 p0, uint256 p1, uint256 p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(string,uint256,uint256,bool)`.\n mstore(0x00, 0x7626db92)\n mstore(0x20, 0x80)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p0)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(bytes32 p0, uint256 p1, uint256 p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n // Selector of `log(string,uint256,uint256,uint256)`.\n mstore(0x00, 0xa7a87853)\n mstore(0x20, 0x80)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p0)\n }\n _sendLogPayload(0x1c, 0xc4);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n }\n }\n\n function log(bytes32 p0, uint256 p1, uint256 p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n // Selector of `log(string,uint256,uint256,string)`.\n mstore(0x00, 0x854b3496)\n mstore(0x20, 0x80)\n mstore(0x40, p1)\n mstore(0x60, p2)\n mstore(0x80, 0xc0)\n writeString(0xa0, p0)\n writeString(0xe0, p3)\n }\n _sendLogPayload(0x1c, 0x104);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n }\n }\n\n function log(bytes32 p0, uint256 p1, bytes32 p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n // Selector of `log(string,uint256,string,address)`.\n mstore(0x00, 0x7c4632a4)\n mstore(0x20, 0x80)\n mstore(0x40, p1)\n mstore(0x60, 0xc0)\n mstore(0x80, p3)\n writeString(0xa0, p0)\n writeString(0xe0, p2)\n }\n _sendLogPayload(0x1c, 0x104);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n }\n }\n\n function log(bytes32 p0, uint256 p1, bytes32 p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n // Selector of `log(string,uint256,string,bool)`.\n mstore(0x00, 0x7d24491d)\n mstore(0x20, 0x80)\n mstore(0x40, p1)\n mstore(0x60, 0xc0)\n mstore(0x80, p3)\n writeString(0xa0, p0)\n writeString(0xe0, p2)\n }\n _sendLogPayload(0x1c, 0x104);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n }\n }\n\n function log(bytes32 p0, uint256 p1, bytes32 p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n // Selector of `log(string,uint256,string,uint256)`.\n mstore(0x00, 0xc67ea9d1)\n mstore(0x20, 0x80)\n mstore(0x40, p1)\n mstore(0x60, 0xc0)\n mstore(0x80, p3)\n writeString(0xa0, p0)\n writeString(0xe0, p2)\n }\n _sendLogPayload(0x1c, 0x104);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n }\n }\n\n function log(bytes32 p0, uint256 p1, bytes32 p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n bytes32 m9;\n bytes32 m10;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n m9 := mload(0x120)\n m10 := mload(0x140)\n // Selector of `log(string,uint256,string,string)`.\n mstore(0x00, 0x5ab84e1f)\n mstore(0x20, 0x80)\n mstore(0x40, p1)\n mstore(0x60, 0xc0)\n mstore(0x80, 0x100)\n writeString(0xa0, p0)\n writeString(0xe0, p2)\n writeString(0x120, p3)\n }\n _sendLogPayload(0x1c, 0x144);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n mstore(0x120, m9)\n mstore(0x140, m10)\n }\n }\n\n function log(bytes32 p0, bytes32 p1, address p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n // Selector of `log(string,string,address,address)`.\n mstore(0x00, 0x439c7bef)\n mstore(0x20, 0x80)\n mstore(0x40, 0xc0)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p0)\n writeString(0xe0, p1)\n }\n _sendLogPayload(0x1c, 0x104);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n }\n }\n\n function log(bytes32 p0, bytes32 p1, address p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n // Selector of `log(string,string,address,bool)`.\n mstore(0x00, 0x5ccd4e37)\n mstore(0x20, 0x80)\n mstore(0x40, 0xc0)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p0)\n writeString(0xe0, p1)\n }\n _sendLogPayload(0x1c, 0x104);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n }\n }\n\n function log(bytes32 p0, bytes32 p1, address p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n // Selector of `log(string,string,address,uint256)`.\n mstore(0x00, 0x7cc3c607)\n mstore(0x20, 0x80)\n mstore(0x40, 0xc0)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p0)\n writeString(0xe0, p1)\n }\n _sendLogPayload(0x1c, 0x104);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n }\n }\n\n function log(bytes32 p0, bytes32 p1, address p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n bytes32 m9;\n bytes32 m10;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n m9 := mload(0x120)\n m10 := mload(0x140)\n // Selector of `log(string,string,address,string)`.\n mstore(0x00, 0xeb1bff80)\n mstore(0x20, 0x80)\n mstore(0x40, 0xc0)\n mstore(0x60, p2)\n mstore(0x80, 0x100)\n writeString(0xa0, p0)\n writeString(0xe0, p1)\n writeString(0x120, p3)\n }\n _sendLogPayload(0x1c, 0x144);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n mstore(0x120, m9)\n mstore(0x140, m10)\n }\n }\n\n function log(bytes32 p0, bytes32 p1, bool p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n // Selector of `log(string,string,bool,address)`.\n mstore(0x00, 0xc371c7db)\n mstore(0x20, 0x80)\n mstore(0x40, 0xc0)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p0)\n writeString(0xe0, p1)\n }\n _sendLogPayload(0x1c, 0x104);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n }\n }\n\n function log(bytes32 p0, bytes32 p1, bool p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n // Selector of `log(string,string,bool,bool)`.\n mstore(0x00, 0x40785869)\n mstore(0x20, 0x80)\n mstore(0x40, 0xc0)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p0)\n writeString(0xe0, p1)\n }\n _sendLogPayload(0x1c, 0x104);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n }\n }\n\n function log(bytes32 p0, bytes32 p1, bool p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n // Selector of `log(string,string,bool,uint256)`.\n mstore(0x00, 0xd6aefad2)\n mstore(0x20, 0x80)\n mstore(0x40, 0xc0)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p0)\n writeString(0xe0, p1)\n }\n _sendLogPayload(0x1c, 0x104);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n }\n }\n\n function log(bytes32 p0, bytes32 p1, bool p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n bytes32 m9;\n bytes32 m10;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n m9 := mload(0x120)\n m10 := mload(0x140)\n // Selector of `log(string,string,bool,string)`.\n mstore(0x00, 0x5e84b0ea)\n mstore(0x20, 0x80)\n mstore(0x40, 0xc0)\n mstore(0x60, p2)\n mstore(0x80, 0x100)\n writeString(0xa0, p0)\n writeString(0xe0, p1)\n writeString(0x120, p3)\n }\n _sendLogPayload(0x1c, 0x144);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n mstore(0x120, m9)\n mstore(0x140, m10)\n }\n }\n\n function log(bytes32 p0, bytes32 p1, uint256 p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n // Selector of `log(string,string,uint256,address)`.\n mstore(0x00, 0x1023f7b2)\n mstore(0x20, 0x80)\n mstore(0x40, 0xc0)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p0)\n writeString(0xe0, p1)\n }\n _sendLogPayload(0x1c, 0x104);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n }\n }\n\n function log(bytes32 p0, bytes32 p1, uint256 p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n // Selector of `log(string,string,uint256,bool)`.\n mstore(0x00, 0xc3a8a654)\n mstore(0x20, 0x80)\n mstore(0x40, 0xc0)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p0)\n writeString(0xe0, p1)\n }\n _sendLogPayload(0x1c, 0x104);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n }\n }\n\n function log(bytes32 p0, bytes32 p1, uint256 p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n // Selector of `log(string,string,uint256,uint256)`.\n mstore(0x00, 0xf45d7d2c)\n mstore(0x20, 0x80)\n mstore(0x40, 0xc0)\n mstore(0x60, p2)\n mstore(0x80, p3)\n writeString(0xa0, p0)\n writeString(0xe0, p1)\n }\n _sendLogPayload(0x1c, 0x104);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n }\n }\n\n function log(bytes32 p0, bytes32 p1, uint256 p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n bytes32 m9;\n bytes32 m10;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n m9 := mload(0x120)\n m10 := mload(0x140)\n // Selector of `log(string,string,uint256,string)`.\n mstore(0x00, 0x5d1a971a)\n mstore(0x20, 0x80)\n mstore(0x40, 0xc0)\n mstore(0x60, p2)\n mstore(0x80, 0x100)\n writeString(0xa0, p0)\n writeString(0xe0, p1)\n writeString(0x120, p3)\n }\n _sendLogPayload(0x1c, 0x144);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n mstore(0x120, m9)\n mstore(0x140, m10)\n }\n }\n\n function log(bytes32 p0, bytes32 p1, bytes32 p2, address p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n bytes32 m9;\n bytes32 m10;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n m9 := mload(0x120)\n m10 := mload(0x140)\n // Selector of `log(string,string,string,address)`.\n mstore(0x00, 0x6d572f44)\n mstore(0x20, 0x80)\n mstore(0x40, 0xc0)\n mstore(0x60, 0x100)\n mstore(0x80, p3)\n writeString(0xa0, p0)\n writeString(0xe0, p1)\n writeString(0x120, p2)\n }\n _sendLogPayload(0x1c, 0x144);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n mstore(0x120, m9)\n mstore(0x140, m10)\n }\n }\n\n function log(bytes32 p0, bytes32 p1, bytes32 p2, bool p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n bytes32 m9;\n bytes32 m10;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n m9 := mload(0x120)\n m10 := mload(0x140)\n // Selector of `log(string,string,string,bool)`.\n mstore(0x00, 0x2c1754ed)\n mstore(0x20, 0x80)\n mstore(0x40, 0xc0)\n mstore(0x60, 0x100)\n mstore(0x80, p3)\n writeString(0xa0, p0)\n writeString(0xe0, p1)\n writeString(0x120, p2)\n }\n _sendLogPayload(0x1c, 0x144);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n mstore(0x120, m9)\n mstore(0x140, m10)\n }\n }\n\n function log(bytes32 p0, bytes32 p1, bytes32 p2, uint256 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n bytes32 m9;\n bytes32 m10;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n m9 := mload(0x120)\n m10 := mload(0x140)\n // Selector of `log(string,string,string,uint256)`.\n mstore(0x00, 0x8eafb02b)\n mstore(0x20, 0x80)\n mstore(0x40, 0xc0)\n mstore(0x60, 0x100)\n mstore(0x80, p3)\n writeString(0xa0, p0)\n writeString(0xe0, p1)\n writeString(0x120, p2)\n }\n _sendLogPayload(0x1c, 0x144);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n mstore(0x120, m9)\n mstore(0x140, m10)\n }\n }\n\n function log(bytes32 p0, bytes32 p1, bytes32 p2, bytes32 p3) internal pure {\n bytes32 m0;\n bytes32 m1;\n bytes32 m2;\n bytes32 m3;\n bytes32 m4;\n bytes32 m5;\n bytes32 m6;\n bytes32 m7;\n bytes32 m8;\n bytes32 m9;\n bytes32 m10;\n bytes32 m11;\n bytes32 m12;\n /// @solidity memory-safe-assembly\n assembly {\n function writeString(pos, w) {\n let length := 0\n for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } }\n mstore(pos, length)\n let shift := sub(256, shl(3, length))\n mstore(add(pos, 0x20), shl(shift, shr(shift, w)))\n }\n m0 := mload(0x00)\n m1 := mload(0x20)\n m2 := mload(0x40)\n m3 := mload(0x60)\n m4 := mload(0x80)\n m5 := mload(0xa0)\n m6 := mload(0xc0)\n m7 := mload(0xe0)\n m8 := mload(0x100)\n m9 := mload(0x120)\n m10 := mload(0x140)\n m11 := mload(0x160)\n m12 := mload(0x180)\n // Selector of `log(string,string,string,string)`.\n mstore(0x00, 0xde68f20a)\n mstore(0x20, 0x80)\n mstore(0x40, 0xc0)\n mstore(0x60, 0x100)\n mstore(0x80, 0x140)\n writeString(0xa0, p0)\n writeString(0xe0, p1)\n writeString(0x120, p2)\n writeString(0x160, p3)\n }\n _sendLogPayload(0x1c, 0x184);\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, m0)\n mstore(0x20, m1)\n mstore(0x40, m2)\n mstore(0x60, m3)\n mstore(0x80, m4)\n mstore(0xa0, m5)\n mstore(0xc0, m6)\n mstore(0xe0, m7)\n mstore(0x100, m8)\n mstore(0x120, m9)\n mstore(0x140, m10)\n mstore(0x160, m11)\n mstore(0x180, m12)\n }\n }\n}\n" + }, + "script/Counter.s.sol": { + "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.13;\n\nimport {Script, console} from \"forge-std/Script.sol\";\nimport {Counter} from \"../src/Counter.sol\";\n\ncontract CounterScript is Script {\n Counter public counter;\n\n function setUp() public {}\n\n function run() public {\n vm.startBroadcast();\n\n counter = new Counter();\n\n vm.stopBroadcast();\n }\n}\n" + }, + "src/Counter.sol": { + "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.13;\n\ncontract Counter {\n uint256 public number;\n\n function setNumber(uint256 newNumber) public {\n number = newNumber;\n }\n\n function increment() public {\n number++;\n }\n}\n" + }, + "test/Counter.t.sol": { + "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.13;\n\nimport {Test, console} from \"forge-std/Test.sol\";\nimport {Counter} from \"../src/Counter.sol\";\n\ncontract CounterTest is Test {\n Counter public counter;\n\n function setUp() public {\n counter = new Counter();\n counter.setNumber(0);\n }\n\n function test_Increment() public {\n counter.increment();\n assertEq(counter.number(), 1);\n }\n\n function testFuzz_SetNumber(uint256 x) public {\n counter.setNumber(x);\n assertEq(counter.number(), x);\n }\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "viaIR": true, + "outputSelection": { + "*": { + "*": [ + "abi", + "metadata", + "devdoc", + "userdoc", + "storageLayout", + "irOptimized", + "ir", + "evm", + "evm.methodIdentifiers", + "evm.legacyAssembly", + "evm.bytecode", + "evm.deployedBytecode", + "evm.assembly" + ], + "": ["ast"] + } + }, + "evmVersion": "berlin", + "remappings": ["forge-std/=lib/forge-std/src/"] + } +} diff --git a/crates/resolc/src/tests/data/standard_json/no_pvm_codegen_per_file.json b/crates/resolc/src/tests/data/standard_json/no_pvm_codegen_per_file.json new file mode 100644 index 0000000..e484e84 --- /dev/null +++ b/crates/resolc/src/tests/data/standard_json/no_pvm_codegen_per_file.json @@ -0,0 +1,720 @@ +{ + "language": "Solidity", + "sources": { + "lib/forge-std/src/interfaces/IERC165.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.6.2;\n\ninterface IERC165 {\n /// @notice Query if a contract implements an interface\n /// @param interfaceID The interface identifier, as specified in ERC-165\n /// @dev Interface identification is specified in ERC-165. This function\n /// uses less than 30,000 gas.\n /// @return `true` if the contract implements `interfaceID` and\n /// `interfaceID` is not 0xffffffff, `false` otherwise\n function supportsInterface(bytes4 interfaceID) external view returns (bool);\n}\n" + }, + "src/common/GasService.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IGasService} from \"src/common/interfaces/IGasService.sol\";\n\n/// @title GasService\n/// @notice This is a utility contract used to determine the execution gas limit\n/// for a payload being sent across all supported adapters.\ncontract GasService is IGasService {\n uint128 internal immutable _maxBatchSize;\n uint128 internal immutable _messageGasLimit;\n\n constructor(uint128 maxBatchSize_, uint128 messageGasLimit) {\n _maxBatchSize = maxBatchSize_;\n _messageGasLimit = messageGasLimit;\n }\n\n /// @inheritdoc IGasService\n function maxBatchSize(uint16) public view returns (uint128) {\n return _maxBatchSize;\n }\n\n /// @inheritdoc IGasService\n function gasLimit(uint16, bytes calldata) public view returns (uint128) {\n return _messageGasLimit;\n }\n}\n" + }, + "src/common/Gateway.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {ArrayLib} from \"src/misc/libraries/ArrayLib.sol\";\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {Recoverable, IRecoverable, ETH_ADDRESS} from \"src/misc/Recoverable.sol\";\nimport {TransientArrayLib} from \"src/misc/libraries/TransientArrayLib.sol\";\nimport {TransientBytesLib} from \"src/misc/libraries/TransientBytesLib.sol\";\nimport {TransientStorageLib} from \"src/misc/libraries/TransientStorageLib.sol\";\n\nimport {IRoot} from \"src/common/interfaces/IRoot.sol\";\nimport {IGasService} from \"src/common/interfaces/IGasService.sol\";\nimport {IAdapter} from \"src/common/interfaces/IAdapter.sol\";\nimport {IMessageProcessor} from \"src/common/interfaces/IMessageProcessor.sol\";\nimport {IMessageSender} from \"src/common/interfaces/IMessageSender.sol\";\nimport {IGateway} from \"src/common/interfaces/IGateway.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {IGatewayHandler} from \"src/common/interfaces/IGatewayHandlers.sol\";\nimport {MessageProofLib} from \"src/common/libraries/MessageProofLib.sol\";\n\n/// @title Gateway\n/// @notice Routing contract that forwards outgoing messages to multiple adapters (1 full message, n-1 proofs)\n/// and validates that multiple adapters have confirmed a message.\n///\n/// Supports batching multiple messages, as well as paying for methods manually or through pool-level subsidies.\n///\n/// Supports processing multiple duplicate messages in parallel by storing counts of messages\n/// and proofs that have been received. Also implements a retry method for failed messages.\ncontract Gateway is Auth, Recoverable, IGateway {\n using BytesLib for bytes;\n using MathLib for uint256;\n using MessageProofLib for *;\n using ArrayLib for uint16[8];\n using TransientStorageLib for bytes32;\n\n uint8 public constant MAX_ADAPTER_COUNT = 8;\n uint8 public constant PRIMARY_ADAPTER_ID = 1;\n PoolId public constant GLOBAL_POT = PoolId.wrap(0);\n uint256 public constant RECOVERY_CHALLENGE_PERIOD = 7 days;\n bytes32 public constant BATCH_LOCATORS_SLOT = bytes32(uint256(keccak256(\"Centrifuge/batch-locators\")) - 1);\n\n uint16 public immutable localCentrifugeId;\n\n // Dependencies\n IRoot public immutable root;\n IGasService public gasService;\n IMessageProcessor public processor;\n\n // Outbound & payments\n bool public transient isBatching;\n uint256 public transient fuel;\n address public transient transactionRefund;\n mapping(PoolId => Funds) public subsidy;\n mapping(uint16 centrifugeId => mapping(bytes32 batchHash => Underpaid)) public underpaid;\n\n // Adapters\n mapping(uint16 centrifugeId => IAdapter[]) public adapters;\n mapping(uint16 centrifugeId => mapping(IAdapter adapter => Adapter)) internal _activeAdapters;\n\n // Inbound & recoveries\n mapping(uint16 centrifugeId => mapping(bytes32 messageHash => uint256)) public failedMessages;\n mapping(uint16 centrifugeId => mapping(bytes32 batchHash => InboundBatch)) public inboundBatch;\n mapping(uint16 centrifugeId => mapping(IAdapter adapter => mapping(bytes32 payloadHash => uint256 timestamp)))\n public recoveries;\n\n constructor(uint16 localCentrifugeId_, IRoot root_, IGasService gasService_, address deployer) Auth(deployer) {\n localCentrifugeId = localCentrifugeId_;\n root = root_;\n gasService = gasService_;\n\n setRefundAddress(GLOBAL_POT, IRecoverable(address(this)));\n }\n\n modifier pauseable() {\n require(!root.paused(), Paused());\n _;\n }\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IGateway\n function file(bytes32 what, uint16 centrifugeId, IAdapter[] calldata addresses) external auth {\n if (what == \"adapters\") {\n uint8 quorum_ = addresses.length.toUint8();\n require(quorum_ != 0, EmptyAdapterSet());\n require(quorum_ <= MAX_ADAPTER_COUNT, ExceedsMax());\n\n // Increment session id to reset pending votes\n uint256 numAdapters = adapters[centrifugeId].length;\n uint64 sessionId =\n numAdapters > 0 ? _activeAdapters[centrifugeId][adapters[centrifugeId][0]].activeSessionId + 1 : 0;\n\n // Disable old adapters\n for (uint8 i; i < numAdapters; i++) {\n delete _activeAdapters[centrifugeId][adapters[centrifugeId][i]];\n }\n\n // Enable new adapters, setting quorum to number of adapters\n for (uint8 j; j < quorum_; j++) {\n require(_activeAdapters[centrifugeId][addresses[j]].id == 0, NoDuplicatesAllowed());\n\n // Ids are assigned sequentially starting at 1\n _activeAdapters[centrifugeId][addresses[j]] = Adapter(j + 1, quorum_, sessionId);\n }\n\n adapters[centrifugeId] = addresses;\n } else {\n revert FileUnrecognizedParam();\n }\n\n emit File(what, centrifugeId, addresses);\n }\n\n /// @inheritdoc IGateway\n function file(bytes32 what, address instance) external auth {\n if (what == \"gasService\") gasService = IGasService(instance);\n else if (what == \"processor\") processor = IMessageProcessor(instance);\n else revert FileUnrecognizedParam();\n\n emit File(what, instance);\n }\n\n receive() external payable {\n _subsidizePool(GLOBAL_POT, msg.sender, msg.value);\n }\n\n //----------------------------------------------------------------------------------------------\n // Incoming\n //----------------------------------------------------------------------------------------------\n\n /// @dev Handle an inbound payload\n function handle(uint16 centrifugeId, bytes calldata payload) external pauseable {\n _handle(centrifugeId, payload, IAdapter(msg.sender), false);\n }\n\n function _handle(uint16 centrifugeId, bytes calldata payload, IAdapter adapter_, bool isRecovery) internal {\n Adapter memory adapter = _activeAdapters[centrifugeId][adapter_];\n require(adapter.id != 0, InvalidAdapter());\n\n IMessageProcessor processor_ = processor;\n if (processor_.isMessageRecovery(payload)) {\n require(!isRecovery, RecoveryPayloadRecovered());\n return processor_.handle(centrifugeId, payload);\n }\n\n bool isMessageProof = payload.toUint8(0) == MessageProofLib.MESSAGE_PROOF_ID;\n\n // Verify adapter and parse message hash\n bytes32 batchHash;\n if (isMessageProof) {\n require(adapter.id != PRIMARY_ADAPTER_ID, NonProofAdapter());\n\n batchHash = payload.deserializeMessageProof();\n bytes32 payloadId = keccak256(abi.encodePacked(centrifugeId, localCentrifugeId, batchHash));\n emit HandleProof(centrifugeId, payloadId, batchHash, adapter_);\n } else {\n require(adapter.id == PRIMARY_ADAPTER_ID, NonBatchAdapter());\n\n batchHash = keccak256(payload);\n bytes32 payloadId = keccak256(abi.encodePacked(centrifugeId, localCentrifugeId, batchHash));\n emit HandleBatch(centrifugeId, payloadId, payload, adapter_);\n }\n\n // Special case for gas efficiency\n if (adapter.quorum == 1 && !isMessageProof) {\n _handleBatch(centrifugeId, payload);\n return;\n }\n\n InboundBatch storage state = inboundBatch[centrifugeId][batchHash];\n\n if (adapter.activeSessionId != state.sessionId) {\n // Clear votes from previous session\n delete state.votes;\n state.sessionId = adapter.activeSessionId;\n }\n\n // Increase vote\n state.votes[adapter.id - 1]++;\n\n if (state.votes.countNonZeroValues() >= adapter.quorum) {\n // Reduce votes by quorum\n state.votes.decreaseFirstNValues(adapter.quorum);\n\n if (isMessageProof) {\n _handleBatch(centrifugeId, state.pendingBatch);\n } else {\n _handleBatch(centrifugeId, payload);\n }\n\n // Only if there are no more pending messages, remove the pending message\n if (state.votes.isEmpty()) {\n delete state.pendingBatch;\n }\n } else if (!isMessageProof) {\n state.pendingBatch = payload;\n }\n }\n\n function _handleBatch(uint16 centrifugeId, bytes memory batch_) internal {\n IMessageProcessor processor_ = processor;\n bytes memory remaining = batch_;\n\n while (remaining.length > 0) {\n uint256 length = processor_.messageLength(remaining);\n bytes memory message = remaining.slice(0, length);\n remaining = remaining.slice(length, remaining.length - length);\n\n try processor_.handle(centrifugeId, message) {\n emit ExecuteMessage(centrifugeId, message);\n } catch (bytes memory err) {\n bytes32 messageHash = keccak256(message);\n failedMessages[centrifugeId][messageHash]++;\n emit FailMessage(centrifugeId, message, err);\n }\n }\n }\n\n /// @inheritdoc IGateway\n function retry(uint16 centrifugeId, bytes memory message) external pauseable {\n bytes32 messageHash = keccak256(message);\n require(failedMessages[centrifugeId][messageHash] > 0, NotFailedMessage());\n\n processor.handle(centrifugeId, message);\n failedMessages[centrifugeId][messageHash]--;\n\n emit ExecuteMessage(centrifugeId, message);\n }\n\n /// @inheritdoc IGatewayHandler\n function initiateRecovery(uint16 centrifugeId, IAdapter adapter, bytes32 payloadHash) external auth {\n require(_activeAdapters[centrifugeId][adapter].id != 0, InvalidAdapter());\n recoveries[centrifugeId][adapter][payloadHash] = block.timestamp + RECOVERY_CHALLENGE_PERIOD;\n emit InitiateRecovery(centrifugeId, payloadHash, adapter);\n }\n\n /// @inheritdoc IGatewayHandler\n function disputeRecovery(uint16 centrifugeId, IAdapter adapter, bytes32 payloadHash) external auth {\n delete recoveries[centrifugeId][adapter][payloadHash];\n emit DisputeRecovery(centrifugeId, payloadHash, adapter);\n }\n\n /// @inheritdoc IGateway\n function executeRecovery(uint16 centrifugeId, IAdapter adapter, bytes calldata payload) external {\n bytes32 payloadHash = keccak256(payload);\n uint256 recovery = recoveries[centrifugeId][adapter][payloadHash];\n\n require(recovery != 0, RecoveryNotInitiated());\n require(recovery <= block.timestamp, RecoveryChallengePeriodNotEnded());\n\n delete recoveries[centrifugeId][adapter][payloadHash];\n _handle(centrifugeId, payload, adapter, true);\n emit ExecuteRecovery(centrifugeId, payload, adapter);\n }\n\n //----------------------------------------------------------------------------------------------\n // Outgoing\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IMessageSender\n function send(uint16 centrifugeId, bytes calldata message) external pauseable auth {\n require(message.length > 0, EmptyMessage());\n\n PoolId poolId = processor.messagePoolId(message);\n\n emit PrepareMessage(centrifugeId, poolId, message);\n\n if (isBatching) {\n bytes32 batchSlot = _outboundBatchSlot(centrifugeId, poolId);\n bytes memory previousMessage = TransientBytesLib.get(batchSlot);\n\n bytes32 gasLimitSlot = _gasLimitSlot(centrifugeId, poolId);\n uint128 newGasLimit = gasLimitSlot.tloadUint128() + gasService.gasLimit(centrifugeId, message);\n require(newGasLimit <= gasService.maxBatchSize(centrifugeId), ExceedsMaxBatchSize());\n gasLimitSlot.tstore(uint256(newGasLimit));\n\n if (previousMessage.length == 0) {\n TransientArrayLib.push(BATCH_LOCATORS_SLOT, _encodeLocator(centrifugeId, poolId));\n }\n\n TransientBytesLib.append(batchSlot, message);\n } else {\n _send(centrifugeId, poolId, message, gasService.gasLimit(centrifugeId, message));\n _refundTransaction();\n }\n }\n\n function _send(uint16 centrifugeId, PoolId poolId, bytes memory batch, uint128 batchGasLimit)\n internal\n returns (bool succeeded)\n {\n IAdapter[] memory adapters_ = adapters[centrifugeId];\n require(adapters[centrifugeId].length != 0, EmptyAdapterSet());\n\n SendData memory data = SendData({\n batchHash: keccak256(batch),\n payloadId: bytes32(\"\"),\n gasCost: new uint256[](MAX_ADAPTER_COUNT)\n });\n data.payloadId = keccak256(abi.encodePacked(localCentrifugeId, centrifugeId, data.batchHash));\n\n {\n // Estimate gas usage\n uint256 total;\n for (uint256 i; i < adapters_.length; i++) {\n data.gasCost[i] = adapters_[i].estimate(\n centrifugeId,\n i == PRIMARY_ADAPTER_ID - 1 ? batch : data.batchHash.serializeMessageProof(),\n batchGasLimit\n );\n\n total += data.gasCost[i];\n }\n\n // Ensure sufficient funds are available\n if (transactionRefund != address(0)) {\n require(total <= fuel, NotEnoughTransactionGas());\n fuel -= total;\n } else {\n if (total > subsidy[poolId].value) {\n _requestPoolFunding(poolId);\n }\n\n if (total <= subsidy[poolId].value) {\n subsidy[poolId].value -= uint96(total);\n } else {\n underpaid[centrifugeId][data.batchHash].counter++;\n underpaid[centrifugeId][data.batchHash].gasLimit = batchGasLimit;\n emit UnderpaidBatch(centrifugeId, batch);\n return false;\n }\n }\n }\n\n // Send batch and proofs\n for (uint256 j; j < adapters_.length; j++) {\n bytes32 adapterData = adapters_[j].send{value: data.gasCost[j]}(\n centrifugeId,\n j == PRIMARY_ADAPTER_ID - 1 ? batch : data.batchHash.serializeMessageProof(),\n batchGasLimit,\n transactionRefund != address(0) ? transactionRefund : address(subsidy[poolId].refund)\n );\n\n if (j == PRIMARY_ADAPTER_ID - 1) {\n emit SendBatch(\n centrifugeId,\n data.payloadId,\n batch,\n adapters_[j],\n adapterData,\n transactionRefund != address(0) ? transactionRefund : address(subsidy[poolId].refund)\n );\n } else {\n emit SendProof(\n centrifugeId,\n data.payloadId,\n data.batchHash,\n adapters_[j],\n adapterData\n );\n }\n }\n\n return true;\n }\n\n /// @inheritdoc IGateway\n function repay(uint16 centrifugeId, bytes memory batch) external payable pauseable {\n bytes32 batchHash = keccak256(batch);\n Underpaid storage underpaid_ = underpaid[centrifugeId][batchHash];\n require(underpaid_.counter > 0, NotUnderpaidBatch());\n\n PoolId poolId = processor.messagePoolId(batch);\n if (msg.value > 0) subsidizePool(poolId);\n\n require(_send(centrifugeId, poolId, batch, underpaid_.gasLimit), InsufficientFundsForRepayment());\n underpaid[centrifugeId][batchHash].counter--;\n\n emit RepayBatch(centrifugeId, batch);\n }\n\n function _refundTransaction() internal {\n if (transactionRefund == address(0)) return;\n\n // Reset before external call\n uint256 fuel_ = fuel;\n address transactionRefund_ = transactionRefund;\n fuel = 0;\n transactionRefund = address(0);\n\n if (fuel_ > 0) {\n (bool success,) = payable(transactionRefund_).call{value: fuel_}(new bytes(0));\n\n if (!success) {\n // If refund fails, move remaining fuel to global pot\n _subsidizePool(GLOBAL_POT, transactionRefund_, fuel_);\n }\n }\n }\n\n function _requestPoolFunding(PoolId poolId) internal {\n IRecoverable refund = subsidy[poolId].refund;\n if (!poolId.isNull() && address(refund) != address(0)) {\n uint256 refundBalance = address(refund).balance;\n if (refundBalance == 0) return;\n\n // Send to the gateway GLOBAL_POT\n refund.recoverTokens(ETH_ADDRESS, address(this), refundBalance);\n\n // Extract from the GLOBAL_POT\n subsidy[GLOBAL_POT].value -= uint96(refundBalance);\n _subsidizePool(poolId, address(refund), refundBalance);\n }\n }\n\n /// @inheritdoc IGateway\n function setRefundAddress(PoolId poolId, IRecoverable refund) public auth {\n subsidy[poolId].refund = refund;\n emit SetRefundAddress(poolId, refund);\n }\n\n /// @inheritdoc IGateway\n function subsidizePool(PoolId poolId) public payable {\n require(address(subsidy[poolId].refund) != address(0), RefundAddressNotSet());\n _subsidizePool(poolId, msg.sender, msg.value);\n }\n\n function _subsidizePool(PoolId poolId, address who, uint256 value) internal {\n subsidy[poolId].value += uint96(value);\n emit SubsidizePool(poolId, who, value);\n }\n\n /// @inheritdoc IGateway\n function payTransaction(address payer) external payable auth {\n transactionRefund = payer;\n fuel += msg.value;\n }\n\n /// @inheritdoc IGateway\n function startBatching() external auth {\n isBatching = true;\n }\n\n /// @inheritdoc IGateway\n function endBatching() external auth {\n require(isBatching, NoBatched());\n\n bytes32[] memory locators = TransientArrayLib.getBytes32(BATCH_LOCATORS_SLOT);\n for (uint256 i; i < locators.length; i++) {\n (uint16 centrifugeId, PoolId poolId) = _parseLocator(locators[i]);\n bytes32 outboundBatchSlot = _outboundBatchSlot(centrifugeId, poolId);\n uint128 gasLimit = _gasLimitSlot(centrifugeId, poolId).tloadUint128();\n\n _send(centrifugeId, poolId, TransientBytesLib.get(outboundBatchSlot), gasLimit);\n\n TransientBytesLib.clear(outboundBatchSlot);\n _gasLimitSlot(centrifugeId, poolId).tstore(uint256(0));\n }\n\n TransientArrayLib.clear(BATCH_LOCATORS_SLOT);\n isBatching = false;\n\n _refundTransaction();\n }\n\n function _encodeLocator(uint16 centrifugeId, PoolId poolId) internal pure returns (bytes32) {\n return bytes32(abi.encodePacked(bytes2(centrifugeId), bytes8(poolId.raw())));\n }\n\n function _parseLocator(bytes32 locator) internal pure returns (uint16 centrifugeId, PoolId poolId) {\n centrifugeId = uint16(bytes2(locator));\n poolId = PoolId.wrap(uint64(bytes8(locator << 16)));\n }\n\n function _gasLimitSlot(uint16 centrifugeId, PoolId poolId) internal pure returns (bytes32) {\n return keccak256(abi.encode(\"batchGasLimit\", centrifugeId, poolId));\n }\n\n function _outboundBatchSlot(uint16 centrifugeId, PoolId poolId) internal pure returns (bytes32) {\n return keccak256(abi.encode(\"outboundBatch\", centrifugeId, poolId));\n }\n\n //----------------------------------------------------------------------------------------------\n // View methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IGateway\n function estimate(uint16 centrifugeId, bytes calldata payload) external view returns (uint256 total) {\n bytes memory proof = keccak256(payload).serializeMessageProof();\n\n uint256 gasLimit = 0;\n for (uint256 pos; pos < payload.length;) {\n bytes calldata inner = payload[pos:payload.length];\n gasLimit += gasService.gasLimit(centrifugeId, inner);\n pos += processor.messageLength(inner);\n }\n\n uint256 adaptersCount = adapters[centrifugeId].length;\n for (uint256 i; i < adaptersCount; i++) {\n bytes memory message = i == PRIMARY_ADAPTER_ID - 1 ? payload : proof;\n total += IAdapter(adapters[centrifugeId][i]).estimate(centrifugeId, message, gasLimit);\n }\n }\n\n /// @inheritdoc IGateway\n function quorum(uint16 centrifugeId) external view returns (uint8) {\n Adapter memory adapter = _activeAdapters[centrifugeId][adapters[centrifugeId][0]];\n return adapter.quorum;\n }\n\n /// @inheritdoc IGateway\n function activeSessionId(uint16 centrifugeId) external view returns (uint64) {\n Adapter memory adapter = _activeAdapters[centrifugeId][adapters[centrifugeId][0]];\n return adapter.activeSessionId;\n }\n\n /// @inheritdoc IGateway\n function votes(uint16 centrifugeId, bytes32 batchHash) external view returns (uint16[MAX_ADAPTER_COUNT] memory) {\n return inboundBatch[centrifugeId][batchHash].votes;\n }\n}\n\n" + }, + "src/common/Guardian.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {IRoot} from \"src/common/interfaces/IRoot.sol\";\nimport {IAdapter} from \"src/common/interfaces/IAdapter.sol\";\nimport {IGuardian, ISafe} from \"src/common/interfaces/IGuardian.sol\";\nimport {IRootMessageSender} from \"src/common/interfaces/IGatewaySenders.sol\";\nimport {IHubGuardianActions} from \"src/common/interfaces/IGuardianActions.sol\";\n\ncontract Guardian is IGuardian {\n using CastLib for address;\n\n IRoot public immutable root;\n\n IHubGuardianActions public hub;\n ISafe public safe;\n IRootMessageSender public sender;\n\n constructor(ISafe safe_, IRoot root_, IRootMessageSender messageDispatcher_) {\n root = root_;\n safe = safe_;\n sender = messageDispatcher_;\n }\n\n modifier onlySafe() {\n require(msg.sender == address(safe), NotTheAuthorizedSafe());\n _;\n }\n\n modifier onlySafeOrOwner() {\n require(msg.sender == address(safe) || _isSafeOwner(msg.sender), NotTheAuthorizedSafeOrItsOwner());\n _;\n }\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IGuardian\n function file(bytes32 what, address data) external onlySafe {\n if (what == \"safe\") safe = ISafe(data);\n else if (what == \"sender\") sender = IRootMessageSender(data);\n else if (what == \"hub\") hub = IHubGuardianActions(data);\n else revert FileUnrecognizedParam();\n\n emit File(what, data);\n }\n\n //----------------------------------------------------------------------------------------------\n // Admin actions\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IGuardian\n function createPool(PoolId poolId, address admin, AssetId currency) external onlySafe {\n return hub.createPool(poolId, admin, currency);\n }\n\n /// @inheritdoc IGuardian\n function pause() external onlySafeOrOwner {\n root.pause();\n }\n\n /// @inheritdoc IGuardian\n function unpause() external onlySafe {\n root.unpause();\n }\n\n /// @inheritdoc IGuardian\n function scheduleRely(address target) external onlySafe {\n root.scheduleRely(target);\n }\n\n /// @inheritdoc IGuardian\n function cancelRely(address target) external onlySafe {\n root.cancelRely(target);\n }\n\n /// @inheritdoc IGuardian\n function scheduleUpgrade(uint16 centrifugeId, address target) external onlySafe {\n sender.sendScheduleUpgrade(centrifugeId, target.toBytes32());\n }\n\n /// @inheritdoc IGuardian\n function cancelUpgrade(uint16 centrifugeId, address target) external onlySafe {\n sender.sendCancelUpgrade(centrifugeId, target.toBytes32());\n }\n\n /// @inheritdoc IGuardian\n function recoverTokens(\n uint16 centrifugeId,\n address target,\n address token,\n uint256 tokenId,\n address to,\n uint256 amount\n ) external onlySafe {\n sender.sendRecoverTokens(centrifugeId, target.toBytes32(), token.toBytes32(), tokenId, to.toBytes32(), amount);\n }\n\n /// @inheritdoc IGuardian\n function initiateRecovery(uint16 centrifugeId, uint16 adapterCentrifugeId, IAdapter adapter, bytes32 hash)\n external\n onlySafe\n {\n sender.sendInitiateRecovery(centrifugeId, adapterCentrifugeId, address(adapter).toBytes32(), hash);\n }\n\n /// @inheritdoc IGuardian\n function disputeRecovery(uint16 centrifugeId, uint16 adapterCentrifugeId, IAdapter adapter, bytes32 hash)\n external\n onlySafe\n {\n sender.sendDisputeRecovery(centrifugeId, adapterCentrifugeId, address(adapter).toBytes32(), hash);\n }\n\n //----------------------------------------------------------------------------------------------\n // Helpers\n //----------------------------------------------------------------------------------------------\n\n function _isSafeOwner(address addr) internal view returns (bool) {\n try safe.isOwner(addr) returns (bool isOwner) {\n return isOwner;\n } catch {\n return false;\n }\n }\n}\n" + }, + "src/common/MessageDispatcher.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {D18, d18} from \"src/misc/types/D18.sol\";\nimport {IRecoverable} from \"src/misc/interfaces/IRecoverable.sol\";\n\nimport {MessageLib} from \"src/common/libraries/MessageLib.sol\";\nimport {IAdapter} from \"src/common/interfaces/IAdapter.sol\";\nimport {IGateway} from \"src/common/interfaces/IGateway.sol\";\nimport {IRoot} from \"src/common/interfaces/IRoot.sol\";\nimport {\n IRequestManagerGatewayHandler,\n IPoolManagerGatewayHandler,\n IBalanceSheetGatewayHandler,\n IHubGatewayHandler\n} from \"src/common/interfaces/IGatewayHandlers.sol\";\nimport {IVaultMessageSender, IPoolMessageSender, IRootMessageSender} from \"src/common/interfaces/IGatewaySenders.sol\";\n\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {IMessageDispatcher} from \"src/common/interfaces/IMessageDispatcher.sol\";\nimport {ITokenRecoverer} from \"src/common/interfaces/ITokenRecoverer.sol\";\n\ncontract MessageDispatcher is Auth, IMessageDispatcher {\n using CastLib for *;\n using MessageLib for *;\n using BytesLib for bytes;\n using MathLib for uint256;\n\n IRoot public immutable root;\n IGateway public immutable gateway;\n ITokenRecoverer public immutable tokenRecoverer;\n\n uint16 public immutable localCentrifugeId;\n\n IHubGatewayHandler public hub;\n IPoolManagerGatewayHandler public poolManager;\n IRequestManagerGatewayHandler public investmentManager;\n IBalanceSheetGatewayHandler public balanceSheet;\n\n constructor(\n uint16 localCentrifugeId_,\n IRoot root_,\n IGateway gateway_,\n ITokenRecoverer tokenRecoverer_,\n address deployer\n ) Auth(deployer) {\n localCentrifugeId = localCentrifugeId_;\n root = root_;\n gateway = gateway_;\n tokenRecoverer = tokenRecoverer_;\n }\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IMessageDispatcher\n function file(bytes32 what, address data) external auth {\n if (what == \"hub\") hub = IHubGatewayHandler(data);\n else if (what == \"poolManager\") poolManager = IPoolManagerGatewayHandler(data);\n else if (what == \"investmentManager\") investmentManager = IRequestManagerGatewayHandler(data);\n else if (what == \"balanceSheet\") balanceSheet = IBalanceSheetGatewayHandler(data);\n else revert FileUnrecognizedParam();\n\n emit File(what, data);\n }\n\n //----------------------------------------------------------------------------------------------\n // Helpers\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IMessageDispatcher\n function estimate(uint16 centrifugeId, bytes calldata payload) external view returns (uint256 amount) {\n if (centrifugeId == localCentrifugeId) return 0;\n return gateway.estimate(centrifugeId, payload);\n }\n\n //----------------------------------------------------------------------------------------------\n // Outgoing\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IPoolMessageSender\n function sendNotifyPool(uint16 centrifugeId, PoolId poolId) external auth {\n if (centrifugeId == localCentrifugeId) {\n poolManager.addPool(poolId);\n } else {\n gateway.send(centrifugeId, MessageLib.NotifyPool({poolId: poolId.raw()}).serialize());\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendNotifyShareClass(\n uint16 centrifugeId,\n PoolId poolId,\n ShareClassId scId,\n string memory name,\n string memory symbol,\n uint8 decimals,\n bytes32 salt,\n bytes32 hook\n ) external auth {\n if (centrifugeId == localCentrifugeId) {\n poolManager.addShareClass(poolId, scId, name, symbol, decimals, salt, hook.toAddress());\n } else {\n gateway.send(\n centrifugeId,\n MessageLib.NotifyShareClass({\n poolId: poolId.raw(),\n scId: scId.raw(),\n name: name,\n symbol: symbol.toBytes32(),\n decimals: decimals,\n salt: salt,\n hook: hook\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendNotifyShareMetadata(\n uint16 centrifugeId,\n PoolId poolId,\n ShareClassId scId,\n string memory name,\n string memory symbol\n ) external auth {\n if (centrifugeId == localCentrifugeId) {\n poolManager.updateShareMetadata(poolId, scId, name, symbol);\n } else {\n gateway.send(\n centrifugeId,\n MessageLib.NotifyShareMetadata({\n poolId: poolId.raw(),\n scId: scId.raw(),\n name: name,\n symbol: symbol.toBytes32()\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendUpdateShareHook(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bytes32 hook) external auth {\n if (centrifugeId == localCentrifugeId) {\n poolManager.updateShareHook(poolId, scId, hook.toAddress());\n } else {\n gateway.send(\n centrifugeId,\n MessageLib.UpdateShareHook({poolId: poolId.raw(), scId: scId.raw(), hook: hook}).serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendNotifyPricePoolPerShare(uint16 chainId, PoolId poolId, ShareClassId scId, D18 sharePrice)\n external\n auth\n {\n uint64 timestamp = block.timestamp.toUint64();\n if (chainId == localCentrifugeId) {\n poolManager.updatePricePoolPerShare(poolId, scId, sharePrice.raw(), timestamp);\n } else {\n gateway.send(\n chainId,\n MessageLib.NotifyPricePoolPerShare({\n poolId: poolId.raw(),\n scId: scId.raw(),\n price: sharePrice.raw(),\n timestamp: timestamp\n }).serialize()\n );\n }\n }\n\n function sendNotifyPricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId, D18 price) external auth {\n uint64 timestamp = block.timestamp.toUint64();\n if (assetId.centrifugeId() == localCentrifugeId) {\n poolManager.updatePricePoolPerAsset(poolId, scId, assetId, price.raw(), timestamp);\n } else {\n gateway.send(\n assetId.centrifugeId(),\n MessageLib.NotifyPricePoolPerAsset({\n poolId: poolId.raw(),\n scId: scId.raw(),\n assetId: assetId.raw(),\n price: price.raw(),\n timestamp: timestamp\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendFulfilledDepositRequest(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n bytes32 investor,\n uint128 assetAmount,\n uint128 shareAmount\n ) external auth {\n if (assetId.centrifugeId() == localCentrifugeId) {\n investmentManager.fulfillDepositRequest(\n poolId, scId, investor.toAddress(), assetId, assetAmount, shareAmount\n );\n } else {\n gateway.send(\n assetId.centrifugeId(),\n MessageLib.FulfilledDepositRequest({\n poolId: poolId.raw(),\n scId: scId.raw(),\n investor: investor,\n assetId: assetId.raw(),\n assetAmount: assetAmount,\n shareAmount: shareAmount\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendFulfilledRedeemRequest(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n bytes32 investor,\n uint128 assetAmount,\n uint128 shareAmount\n ) external auth {\n if (assetId.centrifugeId() == localCentrifugeId) {\n investmentManager.fulfillRedeemRequest(\n poolId, scId, investor.toAddress(), assetId, assetAmount, shareAmount\n );\n } else {\n gateway.send(\n assetId.centrifugeId(),\n MessageLib.FulfilledRedeemRequest({\n poolId: poolId.raw(),\n scId: scId.raw(),\n investor: investor,\n assetId: assetId.raw(),\n assetAmount: assetAmount,\n shareAmount: shareAmount\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendFulfilledCancelDepositRequest(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n bytes32 investor,\n uint128 cancelledAmount\n ) external auth {\n if (assetId.centrifugeId() == localCentrifugeId) {\n investmentManager.fulfillCancelDepositRequest(\n poolId, scId, investor.toAddress(), assetId, cancelledAmount, cancelledAmount\n );\n } else {\n gateway.send(\n assetId.centrifugeId(),\n MessageLib.FulfilledCancelDepositRequest({\n poolId: poolId.raw(),\n scId: scId.raw(),\n investor: investor,\n assetId: assetId.raw(),\n cancelledAmount: cancelledAmount\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendFulfilledCancelRedeemRequest(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n bytes32 investor,\n uint128 cancelledShares\n ) external auth {\n if (assetId.centrifugeId() == localCentrifugeId) {\n investmentManager.fulfillCancelRedeemRequest(poolId, scId, investor.toAddress(), assetId, cancelledShares);\n } else {\n gateway.send(\n assetId.centrifugeId(),\n MessageLib.FulfilledCancelRedeemRequest({\n poolId: poolId.raw(),\n scId: scId.raw(),\n investor: investor,\n assetId: assetId.raw(),\n cancelledShares: cancelledShares\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendUpdateRestriction(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bytes calldata payload)\n external\n auth\n {\n if (centrifugeId == localCentrifugeId) {\n poolManager.updateRestriction(poolId, scId, payload);\n } else {\n gateway.send(\n centrifugeId,\n MessageLib.UpdateRestriction({poolId: poolId.raw(), scId: scId.raw(), payload: payload}).serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendUpdateContract(\n uint16 centrifugeId,\n PoolId poolId,\n ShareClassId scId,\n bytes32 target,\n bytes calldata payload\n ) external auth {\n if (centrifugeId == localCentrifugeId) {\n poolManager.updateContract(poolId, scId, target.toAddress(), payload);\n } else {\n gateway.send(\n centrifugeId,\n MessageLib.UpdateContract({poolId: poolId.raw(), scId: scId.raw(), target: target, payload: payload})\n .serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendApprovedDeposits(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n uint128 assetAmount,\n D18 pricePoolPerAsset\n ) external auth {\n if (assetId.centrifugeId() == localCentrifugeId) {\n investmentManager.approvedDeposits(poolId, scId, assetId, assetAmount, pricePoolPerAsset);\n } else {\n gateway.send(\n assetId.centrifugeId(),\n MessageLib.ApprovedDeposits({\n poolId: poolId.raw(),\n scId: scId.raw(),\n assetId: assetId.raw(),\n assetAmount: assetAmount,\n pricePoolPerAsset: pricePoolPerAsset.raw()\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendIssuedShares(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n uint128 shareAmount,\n D18 pricePoolPerShare\n ) external auth {\n if (assetId.centrifugeId() == localCentrifugeId) {\n investmentManager.issuedShares(poolId, scId, shareAmount, pricePoolPerShare);\n } else {\n gateway.send(\n assetId.centrifugeId(),\n MessageLib.IssuedShares({\n poolId: poolId.raw(),\n scId: scId.raw(),\n shareAmount: shareAmount,\n pricePoolPerShare: pricePoolPerShare.raw()\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendRevokedShares(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n uint128 assetAmount,\n uint128 shareAmount,\n D18 pricePoolPerShare\n ) external auth {\n if (assetId.centrifugeId() == localCentrifugeId) {\n investmentManager.revokedShares(poolId, scId, assetId, assetAmount, shareAmount, pricePoolPerShare);\n } else {\n gateway.send(\n assetId.centrifugeId(),\n MessageLib.RevokedShares({\n poolId: poolId.raw(),\n scId: scId.raw(),\n assetId: assetId.raw(),\n assetAmount: assetAmount,\n shareAmount: shareAmount,\n pricePoolPerShare: pricePoolPerShare.raw()\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendTriggerIssueShares(uint16 centrifugeId, PoolId poolId, ShareClassId scId, address who, uint128 shares)\n external\n auth\n {\n if (centrifugeId == localCentrifugeId) {\n balanceSheet.triggerIssueShares(poolId, scId, who, shares);\n } else {\n gateway.send(\n centrifugeId,\n MessageLib.TriggerIssueShares({\n poolId: poolId.raw(),\n scId: scId.raw(),\n who: who.toBytes32(),\n shares: shares\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendTriggerSubmitQueuedShares(uint16 centrifugeId, PoolId poolId, ShareClassId scId) external auth {\n if (centrifugeId == localCentrifugeId) {\n balanceSheet.submitQueuedShares(poolId, scId);\n } else {\n gateway.send(\n centrifugeId, MessageLib.TriggerSubmitQueuedShares({poolId: poolId.raw(), scId: scId.raw()}).serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendTriggerSubmitQueuedAssets(PoolId poolId, ShareClassId scId, AssetId assetId) external auth {\n if (assetId.centrifugeId() == localCentrifugeId) {\n balanceSheet.submitQueuedAssets(poolId, scId, assetId);\n } else {\n gateway.send(\n assetId.centrifugeId(),\n MessageLib.TriggerSubmitQueuedAssets({poolId: poolId.raw(), scId: scId.raw(), assetId: assetId.raw()})\n .serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendSetQueue(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bool enabled) external auth {\n if (centrifugeId == localCentrifugeId) {\n balanceSheet.setQueue(poolId, scId, enabled);\n } else {\n gateway.send(\n centrifugeId,\n MessageLib.SetQueue({poolId: poolId.raw(), scId: scId.raw(), enabled: enabled}).serialize()\n );\n }\n }\n\n /// @inheritdoc IRootMessageSender\n function sendScheduleUpgrade(uint16 centrifugeId, bytes32 target) external auth {\n if (centrifugeId == localCentrifugeId) {\n root.scheduleRely(target.toAddress());\n } else {\n gateway.send(centrifugeId, MessageLib.ScheduleUpgrade({target: target}).serialize());\n }\n }\n\n /// @inheritdoc IRootMessageSender\n function sendCancelUpgrade(uint16 centrifugeId, bytes32 target) external auth {\n if (centrifugeId == localCentrifugeId) {\n root.cancelRely(target.toAddress());\n } else {\n gateway.send(centrifugeId, MessageLib.CancelUpgrade({target: target}).serialize());\n }\n }\n\n /// @inheritdoc IRootMessageSender\n function sendRecoverTokens(\n uint16 centrifugeId,\n bytes32 target,\n bytes32 token,\n uint256 tokenId,\n bytes32 to,\n uint256 amount\n ) external auth {\n if (centrifugeId == localCentrifugeId) {\n tokenRecoverer.recoverTokens(\n IRecoverable(target.toAddress()), token.toAddress(), tokenId, to.toAddress(), amount\n );\n } else {\n gateway.send(\n centrifugeId,\n MessageLib.RecoverTokens({target: target, token: token, tokenId: tokenId, to: to, amount: amount})\n .serialize()\n );\n }\n }\n\n /// @inheritdoc IRootMessageSender\n function sendInitiateRecovery(uint16 centrifugeId, uint16 adapterCentrifugeId, bytes32 adapter, bytes32 hash)\n external\n auth\n {\n if (centrifugeId == localCentrifugeId) {\n gateway.initiateRecovery(adapterCentrifugeId, IAdapter(adapter.toAddress()), hash);\n } else {\n gateway.send(\n centrifugeId,\n MessageLib.InitiateRecovery({hash: hash, adapter: adapter, centrifugeId: adapterCentrifugeId}).serialize(\n )\n );\n }\n }\n\n /// @inheritdoc IRootMessageSender\n function sendDisputeRecovery(uint16 centrifugeId, uint16 adapterCentrifugeId, bytes32 adapter, bytes32 hash)\n external\n auth\n {\n if (centrifugeId == localCentrifugeId) {\n gateway.disputeRecovery(adapterCentrifugeId, IAdapter(adapter.toAddress()), hash);\n } else {\n gateway.send(\n centrifugeId,\n MessageLib.DisputeRecovery({hash: hash, adapter: adapter, centrifugeId: adapterCentrifugeId}).serialize(\n )\n );\n }\n }\n\n /// @inheritdoc IVaultMessageSender\n function sendTransferShares(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bytes32 receiver, uint128 amount)\n external\n auth\n {\n if (centrifugeId == localCentrifugeId) {\n poolManager.handleTransferShares(poolId, scId, receiver.toAddress(), amount);\n } else {\n gateway.send(\n centrifugeId,\n MessageLib.TransferShares({poolId: poolId.raw(), scId: scId.raw(), receiver: receiver, amount: amount})\n .serialize()\n );\n }\n }\n\n /// @inheritdoc IVaultMessageSender\n function sendDepositRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId assetId, uint128 amount)\n external\n auth\n {\n if (poolId.centrifugeId() == localCentrifugeId) {\n hub.depositRequest(poolId, scId, investor, assetId, amount);\n } else {\n gateway.send(\n poolId.centrifugeId(),\n MessageLib.DepositRequest({\n poolId: poolId.raw(),\n scId: scId.raw(),\n investor: investor,\n assetId: assetId.raw(),\n amount: amount\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IVaultMessageSender\n function sendRedeemRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId assetId, uint128 amount)\n external\n auth\n {\n if (poolId.centrifugeId() == localCentrifugeId) {\n hub.redeemRequest(poolId, scId, investor, assetId, amount);\n } else {\n gateway.send(\n poolId.centrifugeId(),\n MessageLib.RedeemRequest({\n poolId: poolId.raw(),\n scId: scId.raw(),\n investor: investor,\n assetId: assetId.raw(),\n amount: amount\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IVaultMessageSender\n function sendCancelDepositRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId assetId)\n external\n auth\n {\n if (poolId.centrifugeId() == localCentrifugeId) {\n hub.cancelDepositRequest(poolId, scId, investor, assetId);\n } else {\n gateway.send(\n poolId.centrifugeId(),\n MessageLib.CancelDepositRequest({\n poolId: poolId.raw(),\n scId: scId.raw(),\n investor: investor,\n assetId: assetId.raw()\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IVaultMessageSender\n function sendCancelRedeemRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId assetId)\n external\n auth\n {\n if (poolId.centrifugeId() == localCentrifugeId) {\n hub.cancelRedeemRequest(poolId, scId, investor, assetId);\n } else {\n gateway.send(\n poolId.centrifugeId(),\n MessageLib.CancelRedeemRequest({\n poolId: poolId.raw(),\n scId: scId.raw(),\n investor: investor,\n assetId: assetId.raw()\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IVaultMessageSender\n function sendUpdateHoldingAmount(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n address provider,\n uint128 amount,\n D18 pricePoolPerAsset,\n bool isIncrease\n ) external auth {\n if (poolId.centrifugeId() == localCentrifugeId) {\n hub.updateHoldingAmount(poolId, scId, assetId, amount, pricePoolPerAsset, isIncrease);\n } else {\n gateway.send(\n poolId.centrifugeId(),\n MessageLib.UpdateHoldingAmount({\n poolId: poolId.raw(),\n scId: scId.raw(),\n assetId: assetId.raw(),\n who: provider.toBytes32(),\n amount: amount,\n pricePerUnit: pricePoolPerAsset.raw(),\n timestamp: uint64(block.timestamp),\n isIncrease: isIncrease\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IVaultMessageSender\n function sendUpdateShares(PoolId poolId, ShareClassId scId, uint128 shares, bool isIssuance) external auth {\n if (poolId.centrifugeId() == localCentrifugeId) {\n if (isIssuance) {\n hub.increaseShareIssuance(poolId, scId, shares);\n } else {\n hub.decreaseShareIssuance(poolId, scId, shares);\n }\n } else {\n gateway.send(\n poolId.centrifugeId(),\n MessageLib.UpdateShares({\n poolId: poolId.raw(),\n scId: scId.raw(),\n shares: shares,\n timestamp: uint64(block.timestamp),\n isIssuance: isIssuance\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IVaultMessageSender\n function sendRegisterAsset(uint16 centrifugeId, AssetId assetId, uint8 decimals) external auth {\n if (centrifugeId == localCentrifugeId) {\n hub.registerAsset(assetId, decimals);\n } else {\n gateway.send(\n centrifugeId, MessageLib.RegisterAsset({assetId: assetId.raw(), decimals: decimals}).serialize()\n );\n }\n }\n}\n" + }, + "src/common/MessageProcessor.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {D18, d18} from \"src/misc/types/D18.sol\";\nimport {IRecoverable} from \"src/misc/interfaces/IRecoverable.sol\";\n\nimport {MessageType, MessageLib} from \"src/common/libraries/MessageLib.sol\";\nimport {IAdapter} from \"src/common/interfaces/IAdapter.sol\";\nimport {IMessageHandler} from \"src/common/interfaces/IMessageHandler.sol\";\nimport {IMessageProcessor} from \"src/common/interfaces/IMessageProcessor.sol\";\nimport {IMessageProperties} from \"src/common/interfaces/IMessageProperties.sol\";\nimport {IRoot} from \"src/common/interfaces/IRoot.sol\";\nimport {\n IGatewayHandler,\n IPoolManagerGatewayHandler,\n IBalanceSheetGatewayHandler,\n IHubGatewayHandler,\n IRequestManagerGatewayHandler\n} from \"src/common/interfaces/IGatewayHandlers.sol\";\n\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ITokenRecoverer} from \"src/common/interfaces/ITokenRecoverer.sol\";\n\ncontract MessageProcessor is Auth, IMessageProcessor {\n using CastLib for *;\n using MessageLib for *;\n using BytesLib for bytes;\n\n IRoot public immutable root;\n ITokenRecoverer public immutable tokenRecoverer;\n\n IGatewayHandler public gateway;\n IHubGatewayHandler public hub;\n IPoolManagerGatewayHandler public poolManager;\n IRequestManagerGatewayHandler public investmentManager;\n IBalanceSheetGatewayHandler public balanceSheet;\n\n constructor(IRoot root_, ITokenRecoverer tokenRecoverer_, address deployer) Auth(deployer) {\n root = root_;\n tokenRecoverer = tokenRecoverer_;\n }\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IMessageProcessor\n function file(bytes32 what, address data) external auth {\n if (what == \"gateway\") gateway = IGatewayHandler(data);\n else if (what == \"hub\") hub = IHubGatewayHandler(data);\n else if (what == \"poolManager\") poolManager = IPoolManagerGatewayHandler(data);\n else if (what == \"investmentManager\") investmentManager = IRequestManagerGatewayHandler(data);\n else if (what == \"balanceSheet\") balanceSheet = IBalanceSheetGatewayHandler(data);\n else revert FileUnrecognizedParam();\n\n emit File(what, data);\n }\n\n //----------------------------------------------------------------------------------------------\n // Handlers\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IMessageHandler\n function handle(uint16, bytes calldata message) external auth {\n MessageType kind = message.messageType();\n\n if (kind == MessageType.InitiateRecovery) {\n MessageLib.InitiateRecovery memory m = message.deserializeInitiateRecovery();\n gateway.initiateRecovery(m.centrifugeId, IAdapter(m.adapter.toAddress()), m.hash);\n } else if (kind == MessageType.DisputeRecovery) {\n MessageLib.DisputeRecovery memory m = message.deserializeDisputeRecovery();\n gateway.disputeRecovery(m.centrifugeId, IAdapter(m.adapter.toAddress()), m.hash);\n } else if (kind == MessageType.ScheduleUpgrade) {\n MessageLib.ScheduleUpgrade memory m = message.deserializeScheduleUpgrade();\n root.scheduleRely(m.target.toAddress());\n } else if (kind == MessageType.CancelUpgrade) {\n MessageLib.CancelUpgrade memory m = message.deserializeCancelUpgrade();\n root.cancelRely(m.target.toAddress());\n } else if (kind == MessageType.RecoverTokens) {\n MessageLib.RecoverTokens memory m = message.deserializeRecoverTokens();\n tokenRecoverer.recoverTokens(\n IRecoverable(m.target.toAddress()), m.token.toAddress(), m.tokenId, m.to.toAddress(), m.amount\n );\n } else if (kind == MessageType.RegisterAsset) {\n MessageLib.RegisterAsset memory m = message.deserializeRegisterAsset();\n hub.registerAsset(AssetId.wrap(m.assetId), m.decimals);\n } else if (kind == MessageType.NotifyPool) {\n poolManager.addPool(PoolId.wrap(MessageLib.deserializeNotifyPool(message).poolId));\n } else if (kind == MessageType.NotifyShareClass) {\n MessageLib.NotifyShareClass memory m = MessageLib.deserializeNotifyShareClass(message);\n poolManager.addShareClass(\n PoolId.wrap(m.poolId),\n ShareClassId.wrap(m.scId),\n m.name,\n m.symbol.toString(),\n m.decimals,\n m.salt,\n m.hook.toAddress()\n );\n } else if (kind == MessageType.NotifyPricePoolPerShare) {\n MessageLib.NotifyPricePoolPerShare memory m = MessageLib.deserializeNotifyPricePoolPerShare(message);\n poolManager.updatePricePoolPerShare(PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.price, m.timestamp);\n } else if (kind == MessageType.NotifyPricePoolPerAsset) {\n MessageLib.NotifyPricePoolPerAsset memory m = MessageLib.deserializeNotifyPricePoolPerAsset(message);\n poolManager.updatePricePoolPerAsset(\n PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), AssetId.wrap(m.assetId), m.price, m.timestamp\n );\n } else if (kind == MessageType.NotifyShareMetadata) {\n MessageLib.NotifyShareMetadata memory m = MessageLib.deserializeNotifyShareMetadata(message);\n poolManager.updateShareMetadata(\n PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.name, m.symbol.toString()\n );\n } else if (kind == MessageType.UpdateShareHook) {\n MessageLib.UpdateShareHook memory m = MessageLib.deserializeUpdateShareHook(message);\n poolManager.updateShareHook(PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.hook.toAddress());\n } else if (kind == MessageType.TransferShares) {\n MessageLib.TransferShares memory m = MessageLib.deserializeTransferShares(message);\n poolManager.handleTransferShares(\n PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.receiver.toAddress(), m.amount\n );\n } else if (kind == MessageType.UpdateRestriction) {\n MessageLib.UpdateRestriction memory m = MessageLib.deserializeUpdateRestriction(message);\n poolManager.updateRestriction(PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.payload);\n } else if (kind == MessageType.UpdateContract) {\n MessageLib.UpdateContract memory m = MessageLib.deserializeUpdateContract(message);\n poolManager.updateContract(\n PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.target.toAddress(), m.payload\n );\n } else if (kind == MessageType.DepositRequest) {\n MessageLib.DepositRequest memory m = message.deserializeDepositRequest();\n hub.depositRequest(\n PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.investor, AssetId.wrap(m.assetId), m.amount\n );\n } else if (kind == MessageType.RedeemRequest) {\n MessageLib.RedeemRequest memory m = message.deserializeRedeemRequest();\n hub.redeemRequest(\n PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.investor, AssetId.wrap(m.assetId), m.amount\n );\n } else if (kind == MessageType.CancelDepositRequest) {\n MessageLib.CancelDepositRequest memory m = message.deserializeCancelDepositRequest();\n hub.cancelDepositRequest(\n PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.investor, AssetId.wrap(m.assetId)\n );\n } else if (kind == MessageType.CancelRedeemRequest) {\n MessageLib.CancelRedeemRequest memory m = message.deserializeCancelRedeemRequest();\n hub.cancelRedeemRequest(\n PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.investor, AssetId.wrap(m.assetId)\n );\n } else if (kind == MessageType.FulfilledDepositRequest) {\n MessageLib.FulfilledDepositRequest memory m = message.deserializeFulfilledDepositRequest();\n investmentManager.fulfillDepositRequest(\n PoolId.wrap(m.poolId),\n ShareClassId.wrap(m.scId),\n m.investor.toAddress(),\n AssetId.wrap(m.assetId),\n m.assetAmount,\n m.shareAmount\n );\n } else if (kind == MessageType.FulfilledRedeemRequest) {\n MessageLib.FulfilledRedeemRequest memory m = message.deserializeFulfilledRedeemRequest();\n investmentManager.fulfillRedeemRequest(\n PoolId.wrap(m.poolId),\n ShareClassId.wrap(m.scId),\n m.investor.toAddress(),\n AssetId.wrap(m.assetId),\n m.assetAmount,\n m.shareAmount\n );\n } else if (kind == MessageType.FulfilledCancelDepositRequest) {\n MessageLib.FulfilledCancelDepositRequest memory m = message.deserializeFulfilledCancelDepositRequest();\n investmentManager.fulfillCancelDepositRequest(\n PoolId.wrap(m.poolId),\n ShareClassId.wrap(m.scId),\n m.investor.toAddress(),\n AssetId.wrap(m.assetId),\n m.cancelledAmount,\n m.cancelledAmount\n );\n } else if (kind == MessageType.FulfilledCancelRedeemRequest) {\n MessageLib.FulfilledCancelRedeemRequest memory m = message.deserializeFulfilledCancelRedeemRequest();\n investmentManager.fulfillCancelRedeemRequest(\n PoolId.wrap(m.poolId),\n ShareClassId.wrap(m.scId),\n m.investor.toAddress(),\n AssetId.wrap(m.assetId),\n m.cancelledShares\n );\n } else if (kind == MessageType.TriggerIssueShares) {\n MessageLib.TriggerIssueShares memory m = message.deserializeTriggerIssueShares();\n balanceSheet.triggerIssueShares(\n PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.who.toAddress(), m.shares\n );\n } else if (kind == MessageType.UpdateHoldingAmount) {\n MessageLib.UpdateHoldingAmount memory m = message.deserializeUpdateHoldingAmount();\n hub.updateHoldingAmount(\n PoolId.wrap(m.poolId),\n ShareClassId.wrap(m.scId),\n AssetId.wrap(m.assetId),\n m.amount,\n D18.wrap(m.pricePerUnit),\n m.isIncrease\n );\n } else if (kind == MessageType.UpdateShares) {\n MessageLib.UpdateShares memory m = message.deserializeUpdateShares();\n if (m.isIssuance) {\n hub.increaseShareIssuance(PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.shares);\n } else {\n hub.decreaseShareIssuance(PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.shares);\n }\n } else if (kind == MessageType.ApprovedDeposits) {\n MessageLib.ApprovedDeposits memory m = message.deserializeApprovedDeposits();\n investmentManager.approvedDeposits(\n PoolId.wrap(m.poolId),\n ShareClassId.wrap(m.scId),\n AssetId.wrap(m.assetId),\n m.assetAmount,\n D18.wrap(m.pricePoolPerAsset)\n );\n } else if (kind == MessageType.IssuedShares) {\n MessageLib.IssuedShares memory m = message.deserializeIssuedShares();\n investmentManager.issuedShares(\n PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.shareAmount, D18.wrap(m.pricePoolPerShare)\n );\n } else if (kind == MessageType.RevokedShares) {\n MessageLib.RevokedShares memory m = message.deserializeRevokedShares();\n investmentManager.revokedShares(\n PoolId.wrap(m.poolId),\n ShareClassId.wrap(m.scId),\n AssetId.wrap(m.assetId),\n m.assetAmount,\n m.shareAmount,\n D18.wrap(m.pricePoolPerShare)\n );\n } else if (kind == MessageType.TriggerSubmitQueuedShares) {\n MessageLib.TriggerSubmitQueuedShares memory m = message.deserializeTriggerSubmitQueuedShares();\n balanceSheet.submitQueuedShares(PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId));\n } else if (kind == MessageType.TriggerSubmitQueuedAssets) {\n MessageLib.TriggerSubmitQueuedAssets memory m = message.deserializeTriggerSubmitQueuedAssets();\n balanceSheet.submitQueuedAssets(PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), AssetId.wrap(m.assetId));\n } else if (kind == MessageType.SetQueue) {\n MessageLib.SetQueue memory m = message.deserializeSetQueue();\n balanceSheet.setQueue(PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.enabled);\n } else {\n revert InvalidMessage(uint8(kind));\n }\n }\n\n /// @inheritdoc IMessageProperties\n function isMessageRecovery(bytes calldata message) external pure returns (bool) {\n uint8 code = message.messageCode();\n return code == uint8(MessageType.InitiateRecovery) || code == uint8(MessageType.DisputeRecovery);\n }\n\n /// @inheritdoc IMessageProperties\n function messageLength(bytes calldata message) external pure returns (uint16) {\n return message.messageLength();\n }\n\n /// @inheritdoc IMessageProperties\n function messagePoolId(bytes calldata message) external pure returns (PoolId) {\n return message.messagePoolId();\n }\n}\n" + }, + "src/common/Root.sol": { + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {IAuth} from \"src/misc/interfaces/IAuth.sol\";\n\nimport {IRoot} from \"src/common/interfaces/IRoot.sol\";\n\n/// @title Root\n/// @notice Core contract that is a ward on all other deployed contracts.\n/// @dev Pausing can happen instantaneously, but relying on other contracts\n/// is restricted to the timelock set by the delay.\ncontract Root is Auth, IRoot {\n /// @dev To prevent filing a delay that would block any updates indefinitely\n uint256 internal constant MAX_DELAY = 4 weeks;\n\n bool public paused;\n uint256 public delay;\n mapping(address => uint256) public endorsements;\n mapping(address relyTarget => uint256 timestamp) public schedule;\n\n constructor(uint256 _delay, address deployer) Auth(deployer) {\n require(_delay <= MAX_DELAY, DelayTooLong());\n delay = _delay;\n }\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IRoot\n function file(bytes32 what, uint256 data) external auth {\n if (what == \"delay\") {\n require(data <= MAX_DELAY, DelayTooLong());\n delay = data;\n } else {\n revert FileUnrecognizedParam();\n }\n emit File(what, data);\n }\n\n /// @inheritdoc IRoot\n function endorse(address user) external auth {\n endorsements[user] = 1;\n emit Endorse(user);\n }\n\n /// @inheritdoc IRoot\n function veto(address user) external auth {\n endorsements[user] = 0;\n emit Veto(user);\n }\n\n /// @inheritdoc IRoot\n function endorsed(address user) external view returns (bool) {\n return endorsements[user] == 1;\n }\n\n //----------------------------------------------------------------------------------------------\n // Pause management\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IRoot\n function pause() external auth {\n paused = true;\n emit Pause();\n }\n\n /// @inheritdoc IRoot\n function unpause() external auth {\n paused = false;\n emit Unpause();\n }\n\n //----------------------------------------------------------------------------------------------\n // Timelocked ward management\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IRoot\n function scheduleRely(address target) external auth {\n schedule[target] = block.timestamp + delay;\n emit ScheduleRely(target, schedule[target]);\n }\n\n /// @inheritdoc IRoot\n function cancelRely(address target) external auth {\n require(schedule[target] != 0, TargetNotScheduled());\n schedule[target] = 0;\n emit CancelRely(target);\n }\n\n /// @inheritdoc IRoot\n function executeScheduledRely(address target) external {\n require(schedule[target] != 0, TargetNotScheduled());\n require(schedule[target] <= block.timestamp, TargetNotReady());\n\n wards[target] = 1;\n emit Rely(target);\n\n schedule[target] = 0;\n }\n\n //----------------------------------------------------------------------------------------------\n // External contract ward management\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IRoot\n function relyContract(address target, address user) external auth {\n IAuth(target).rely(user);\n emit RelyContract(target, user);\n }\n\n /// @inheritdoc IRoot\n function denyContract(address target, address user) external auth {\n IAuth(target).deny(user);\n emit DenyContract(target, user);\n }\n}\n" + }, + "src/common/TokenRecoverer.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {IRecoverable} from \"src/misc/interfaces/IRecoverable.sol\";\n\nimport {IRoot} from \"src/common/interfaces/IRoot.sol\";\nimport {ITokenRecoverer} from \"src/common/interfaces/ITokenRecoverer.sol\";\nimport {IRecoverable} from \"src/misc/interfaces/IRecoverable.sol\";\n\ncontract TokenRecoverer is Auth, ITokenRecoverer {\n IRoot public immutable root;\n\n constructor(IRoot root_, address deployer) Auth(deployer) {\n root = root_;\n }\n\n /// @notice inheritdoc ITokenRecoverer\n function recoverTokens(IRecoverable target, address token, uint256 tokenId, address to, uint256 amount)\n external\n auth\n {\n root.relyContract(address(target), address(this));\n\n if (tokenId == 0) {\n target.recoverTokens(token, to, amount);\n } else {\n target.recoverTokens(token, tokenId, to, amount);\n }\n\n root.denyContract(address(target), address(this));\n\n emit RecoverTokens(target, token, tokenId, to, amount);\n }\n}\n" + }, + "src/common/adapters/AxelarAdapter.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {\n IAxelarAdapter,\n IAdapter,\n IAxelarGateway,\n IAxelarGasService,\n AxelarSource,\n AxelarDestination,\n IAxelarExecutable\n} from \"src/common/interfaces/IAxelarAdapter.sol\";\nimport {IMessageHandler} from \"src/common/interfaces/IMessageHandler.sol\";\n\n/// @title Axelar Adapter\n/// @notice Routing contract that integrates with an Axelar Gateway\ncontract AxelarAdapter is Auth, IAxelarAdapter {\n using CastLib for *;\n\n IMessageHandler public immutable gateway;\n IAxelarGateway public immutable axelarGateway;\n IAxelarGasService public immutable axelarGasService;\n\n mapping(string axelarId => AxelarSource) public sources;\n mapping(uint16 centrifugeId => AxelarDestination) public destinations;\n\n constructor(IMessageHandler gateway_, address axelarGateway_, address axelarGasService_, address deployer)\n Auth(deployer)\n {\n gateway = gateway_;\n axelarGateway = IAxelarGateway(axelarGateway_);\n axelarGasService = IAxelarGasService(axelarGasService_);\n }\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IAxelarAdapter\n function file(bytes32 what, string calldata axelarId, uint16 centrifugeId, string calldata source) external auth {\n if (what == \"sources\") sources[axelarId] = AxelarSource(centrifugeId, keccak256(bytes(source)));\n else revert FileUnrecognizedParam();\n emit File(what, axelarId, centrifugeId, source);\n }\n\n /// @inheritdoc IAxelarAdapter\n function file(bytes32 what, uint16 centrifugeId, string calldata axelarId, string calldata destination)\n external\n auth\n {\n if (what == \"destinations\") destinations[centrifugeId] = AxelarDestination(axelarId, destination);\n else revert FileUnrecognizedParam();\n emit File(what, centrifugeId, axelarId, destination);\n }\n\n //----------------------------------------------------------------------------------------------\n // Incoming\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IAxelarExecutable\n function execute(\n bytes32 commandId,\n string calldata sourceAxelarId,\n string calldata sourceAddress,\n bytes calldata payload\n ) public {\n AxelarSource memory source = sources[sourceAxelarId];\n require(\n source.addressHash != bytes32(\"\") && source.addressHash == keccak256(bytes(sourceAddress)), InvalidAddress()\n );\n\n require(\n axelarGateway.validateContractCall(commandId, sourceAxelarId, sourceAddress, keccak256(payload)),\n NotApprovedByGateway()\n );\n\n gateway.handle(source.centrifugeId, payload);\n }\n\n //----------------------------------------------------------------------------------------------\n // Outgoing\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IAdapter\n function send(uint16 centrifugeId, bytes calldata payload, uint256, /* gasLimit */ address refund)\n external\n payable\n returns (bytes32 adapterData)\n {\n require(msg.sender == address(gateway), NotGateway());\n AxelarDestination memory destination = destinations[centrifugeId];\n require(bytes(destination.axelarId).length != 0, UnknownChainId());\n\n axelarGasService.payNativeGasForContractCall{value: msg.value}(\n address(this), destination.axelarId, destination.addr, payload, refund\n );\n\n axelarGateway.callContract(destination.axelarId, destination.addr, payload);\n\n adapterData = bytes32(\"\");\n }\n\n /// @inheritdoc IAdapter\n function estimate(uint16 centrifugeId, bytes calldata payload, uint256 gasLimit) public view returns (uint256) {\n AxelarDestination memory destination = destinations[centrifugeId];\n return axelarGasService.estimateGasFee(destination.axelarId, destination.addr, payload, gasLimit, bytes(\"\"));\n }\n}\n" + }, + "src/common/adapters/WormholeAdapter.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {IMessageHandler} from \"src/common/interfaces/IMessageHandler.sol\";\nimport {\n IWormholeAdapter,\n IAdapter,\n IWormholeRelayer,\n IWormholeDeliveryProvider,\n IWormholeReceiver,\n WormholeSource,\n WormholeDestination\n} from \"src/common/interfaces/IWormholeAdapter.sol\";\n\n/// @title Wormhole Adapter\n/// @notice Routing contract that integrates with the Wormhole Relayer service\ncontract WormholeAdapter is Auth, IWormholeAdapter {\n using CastLib for bytes32;\n\n uint16 public immutable localWormholeId;\n IMessageHandler public immutable gateway;\n IWormholeRelayer public immutable relayer;\n\n mapping(uint16 wormholeId => WormholeSource) public sources;\n mapping(uint16 centrifugeId => WormholeDestination) public destinations;\n\n constructor(IMessageHandler gateway_, address relayer_, address deployer) Auth(deployer) {\n gateway = gateway_;\n relayer = IWormholeRelayer(relayer_);\n\n IWormholeDeliveryProvider deliveryProvider = IWormholeDeliveryProvider(relayer.getDefaultDeliveryProvider());\n localWormholeId = deliveryProvider.chainId();\n }\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IWormholeAdapter\n function file(bytes32 what, uint16 centrifugeId, uint16 wormholeId, address addr) external auth {\n if (what == \"sources\") sources[wormholeId] = WormholeSource(centrifugeId, addr);\n else if (what == \"destinations\") destinations[centrifugeId] = WormholeDestination(wormholeId, addr);\n else revert FileUnrecognizedParam();\n emit File(what, centrifugeId, wormholeId, addr);\n }\n\n //----------------------------------------------------------------------------------------------\n // Incoming\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IWormholeReceiver\n function receiveWormholeMessages(\n bytes memory payload,\n bytes[] memory, /* additionalVaas */\n bytes32 sourceAddress,\n uint16 sourceWormholeId,\n bytes32 /* deliveryHash */\n ) external payable {\n WormholeSource memory source = sources[sourceWormholeId];\n require(source.addr != address(0) && source.addr == sourceAddress.toAddressLeftPadded(), InvalidSource());\n require(msg.sender == address(relayer), NotWormholeRelayer());\n\n gateway.handle(source.centrifugeId, payload);\n }\n\n //----------------------------------------------------------------------------------------------\n // Outgoing\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IAdapter\n function send(uint16 centrifugeId, bytes calldata payload, uint256 gasLimit, address refund)\n external\n payable\n returns (bytes32 adapterData)\n {\n require(msg.sender == address(gateway), NotGateway());\n WormholeDestination memory destination = destinations[centrifugeId];\n require(destination.wormholeId != 0, UnknownChainId());\n\n uint64 sequence = relayer.sendPayloadToEvm{value: msg.value}(\n destination.wormholeId, destination.addr, payload, 0, gasLimit, localWormholeId, refund\n );\n\n adapterData = bytes32(bytes8(sequence));\n }\n\n /// @inheritdoc IAdapter\n function estimate(uint16 centrifugeId, bytes calldata, uint256 gasLimit)\n public\n view\n returns (uint256 nativePriceQuote)\n {\n (nativePriceQuote,) = relayer.quoteEVMDeliveryPrice(destinations[centrifugeId].wormholeId, 0, gasLimit);\n }\n}\n" + }, + "src/common/interfaces/IAdapter.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IAuth} from \"src/misc/interfaces/IAuth.sol\";\n\ninterface IAdapter is IAuth {\n error NotGateway();\n error UnknownChainId();\n\n /// @notice Send a payload to the destination chain\n function send(uint16 centrifugeId, bytes calldata payload, uint256 gasLimit, address refund)\n external\n payable\n returns (bytes32 adapterData);\n\n /// @notice Estimate the total cost in native gas tokens\n function estimate(uint16 centrifugeId, bytes calldata payload, uint256 gasLimit) external view returns (uint256);\n}\n" + }, + "src/common/interfaces/IAxelarAdapter.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IAdapter} from \"src/common/interfaces/IAdapter.sol\";\n\n// From https://github.com/axelarnetwork/axelar-cgp-solidity/blob/main/contracts/interfaces/IAxelarGateway.sol\ninterface IAxelarGateway {\n function callContract(string calldata destinationChain, string calldata contractAddress, bytes calldata payload)\n external;\n\n function validateContractCall(\n bytes32 commandId,\n string calldata sourceChain,\n string calldata sourceAddress,\n bytes32 payloadHash\n ) external returns (bool);\n}\n\ninterface IAxelarGasService {\n // From\n // https://github.com/axelarnetwork/axelar-gmp-sdk-solidity/blob/00682b6c3db0cc922ec0c4ea3791852c93d7ae31/contracts/gas-estimation/InterchainGasEstimation.sol#L48\n function estimateGasFee(\n string calldata destinationChain,\n string calldata destinationAddress,\n bytes calldata payload,\n uint256 executionGasLimit,\n bytes calldata params\n ) external view returns (uint256 gasEstimate);\n\n // From https://github.com/axelarnetwork/axelar-cgp-solidity/blob/main/contracts/interfaces/IAxelarGasService.sol\n function payNativeGasForContractCall(\n address sender,\n string calldata destinationChain,\n string calldata destinationAddress,\n bytes calldata payload,\n address refundAddress\n ) external payable;\n}\n\n// From\n// https://github.com/axelarnetwork/axelar-gmp-sdk-solidity/blob/00682b6c3db0cc922ec0c4ea3791852c93d7ae31/contracts/interfaces/IAxelarExecutable.sol#L14\ninterface IAxelarExecutable {\n /**\n * @dev Thrown when a function is called with an invalid address.\n */\n error InvalidAddress();\n\n /**\n * @dev Thrown when the call is not approved by the Axelar Gateway.\n */\n error NotApprovedByGateway();\n\n /**\n * @notice Executes the specified command sent from another chain.\n * @dev This function is called by the Axelar Gateway to carry out cross-chain commands.\n * Reverts if the call is not approved by the gateway or other checks fail.\n * @param commandId The identifier of the command to execute.\n * @param sourceChain The name of the source chain from where the command originated.\n * @param sourceAddress The address on the source chain that sent the command.\n * @param payload The payload of the command to be executed. This typically includes the function selector and\n * encoded arguments.\n */\n function execute(\n bytes32 commandId,\n string calldata sourceChain,\n string calldata sourceAddress,\n bytes calldata payload\n ) external;\n}\n\nstruct AxelarSource {\n uint16 centrifugeId;\n bytes32 addressHash;\n}\n\nstruct AxelarDestination {\n string axelarId;\n string addr;\n}\n\ninterface IAxelarAdapter is IAdapter, IAxelarExecutable {\n event File(bytes32 indexed what, string axelarId, uint16 centrifugeId, string source);\n event File(bytes32 indexed what, uint16 centrifugeId, string axelarId, string destination);\n\n error FileUnrecognizedParam();\n\n function file(bytes32 what, string calldata axelarId, uint16 centrifugeId, string calldata source) external;\n function file(bytes32 what, uint16 centrifugeId, string calldata axelarId, string calldata destination) external;\n}\n" + }, + "src/common/interfaces/IGasService.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\ninterface IGasService {\n /// @notice Gas limit for the execution cost of an individual message in a remote chain.\n /// @dev NOTE: In the future we could want to dispatch:\n /// - by destination chain (for non-EVM chains)\n /// - by message type\n /// - by inspecting the payload checking different subsmessages that alter the endpoint processing\n /// @param centrifugeId Where to the cost is defined\n /// @param message Individual message\n /// @return Estimated cost in WEI units\n function gasLimit(uint16 centrifugeId, bytes calldata message) external view returns (uint128);\n\n /// @notice Gas limit for the execution cost of a batch in a remote chain.\n /// @param centrifugeId Where to the cost is defined\n /// @return Max cost in WEI units\n function maxBatchSize(uint16 centrifugeId) external view returns (uint128);\n}\n" + }, + "src/common/interfaces/IGateway.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IRecoverable} from \"src/misc/interfaces/IRecoverable.sol\";\n\nimport {IGatewayHandler} from \"src/common/interfaces/IGatewayHandlers.sol\";\nimport {IMessageHandler} from \"src/common/interfaces/IMessageHandler.sol\";\nimport {IMessageSender} from \"src/common/interfaces/IMessageSender.sol\";\nimport {IAdapter} from \"src/common/interfaces/IAdapter.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\n\nuint8 constant MAX_ADAPTER_COUNT = 8;\n\n/// @notice Interface for dispatch-only gateway\ninterface IGateway is IMessageHandler, IMessageSender, IGatewayHandler {\n /// @dev Each adapter struct is packed with the quorum to reduce SLOADs on handle\n struct Adapter {\n /// @notice Starts at 1 and maps to id - 1 as the index on the adapters array\n uint8 id;\n /// @notice Number of votes required for a message to be executed\n uint8 quorum;\n /// @notice Each time the quorum is decreased, a new session starts which invalidates old votes\n uint64 activeSessionId;\n }\n\n struct InboundBatch {\n /// @dev Counts are stored as integers (instead of boolean values) to accommodate duplicate\n /// messages (e.g. two investments from the same user with the same amount) being\n /// processed in parallel. The entire struct is packed in a single bytes32 slot.\n /// Max uint16 = 65,535 so at most 65,535 duplicate messages can be processed in parallel.\n uint16[MAX_ADAPTER_COUNT] votes;\n /// @notice Each time adapters are updated, a new session starts which invalidates old votes\n uint64 sessionId;\n bytes pendingBatch;\n }\n\n struct Funds {\n /// @notice Funds associated to pay for sending messages\n /// @dev Overflows with type(uint64).max / 10**18 = 7.923 × 10^10 ETH\n uint96 value;\n /// @notice Address where to refund the remaining gas\n IRecoverable refund;\n }\n\n // Used to bypass stack too deep issue\n struct SendData {\n bytes32 batchHash;\n bytes32 payloadId;\n uint256[] gasCost;\n }\n\n struct Underpaid {\n uint128 counter;\n uint128 gasLimit;\n }\n\n // --- Events ---\n event PrepareMessage(uint16 indexed centrifugeId, PoolId poolId, bytes message);\n event UnderpaidBatch(uint16 indexed centrifugeId, bytes batch);\n event RepayBatch(uint16 indexed centrifugeId, bytes batch);\n event SendBatch(\n uint16 indexed centrifugeId,\n bytes32 indexed payloadId,\n bytes batch,\n IAdapter adapter,\n bytes32 adapterData,\n address refund\n );\n event SendProof(\n uint16 indexed centrifugeId, bytes32 indexed payloadId, bytes32 batchHash, IAdapter adapter, bytes32 adapterData\n );\n event HandleBatch(uint16 indexed centrifugeId, bytes32 indexed payloadId, bytes batch, IAdapter adapter);\n event HandleProof(uint16 indexed centrifugeId, bytes32 indexed payloadId, bytes32 batchHash, IAdapter adapter);\n event ExecuteMessage(uint16 indexed centrifugeId, bytes message);\n event FailMessage(uint16 indexed centrifugeId, bytes message, bytes error);\n\n event RecoverMessage(IAdapter adapter, bytes message);\n event RecoverProof(IAdapter adapter, bytes32 batchHash);\n event InitiateRecovery(uint16 centrifugeId, bytes32 batchHash, IAdapter adapter);\n event DisputeRecovery(uint16 centrifugeId, bytes32 batchHash, IAdapter adapter);\n event ExecuteRecovery(uint16 centrifugeId, bytes message, IAdapter adapter);\n\n event File(bytes32 indexed what, uint16 centrifugeId, IAdapter[] adapters);\n event File(bytes32 indexed what, address addr);\n\n event SetRefundAddress(PoolId poolId, IRecoverable refund);\n event SubsidizePool(PoolId indexed poolId, address indexed sender, uint256 amount);\n\n /// @notice Dispatched when the `what` parameter of `file()` is not supported by the implementation.\n error FileUnrecognizedParam();\n\n /// @notice Dispatched when the batch is ended without starting it.\n error NoBatched();\n\n /// @notice Dispatched when the gateway is paused.\n error Paused();\n\n /// @notice Dispatched when the gateway is configured with a number of adapter exceeding the maximum.\n error ExceedsMax();\n\n /// @notice Dispatched when the gateway is configured with an empty adapter set.\n error EmptyAdapterSet();\n\n /// @notice Dispatched when the gateway is configured with duplicate adapters.\n error NoDuplicatesAllowed();\n\n /// @notice Dispatched when the gateway tries to handle a message from an adaptet not contained in the adapter set.\n error InvalidAdapter();\n\n /// @notice Dispatched when the gateway tries to recover a recovery message, which is not allowed.\n error RecoveryPayloadRecovered();\n\n /// @notice Dispatched when the gateway tries to handle a proof from a non proof adapter.\n error NonProofAdapter();\n\n /// @notice Dispatched when the gateway tries to handle a batch from a non message adapter.\n error NonBatchAdapter();\n\n /// @notice Dispatched when a recovery message is executed without being initiated.\n error RecoveryNotInitiated();\n\n /// @notice Dispatched when a recovery message is executed without waiting the challenge period.\n error RecoveryChallengePeriodNotEnded();\n\n /// @notice Dispatched when a the gateway tries to send an empty message.\n error EmptyMessage();\n\n /// @notice Dispatched when a the gateway has not enough fuel to send a message.\n /// Only dispatched in PayTransaction method\n error NotEnoughTransactionGas();\n\n /// @notice Dispatched when a message that has not failed is retried.\n error NotFailedMessage();\n\n /// @notice Dispatched when a batch that has not been underpaid is repaid.\n error NotUnderpaidBatch();\n\n /// @notice Dispatched when a batch is repaid with insufficient funds.\n error InsufficientFundsForRepayment();\n\n /// @notice Dispatched when a message is added to a batch that causes it to exceed the max batch size.\n error ExceedsMaxBatchSize();\n\n /// @notice Dispatched when a refund address is not set.\n error RefundAddressNotSet();\n\n // --- Administration ---\n /// @notice Used to update an array of addresses ( state variable ) on very rare occasions.\n /// @dev Currently it is used to update the supported adapters.\n /// @param what The name of the variable to be updated.\n /// @param centrifugeId Chain where the adapters are associated to.\n /// @param value New addresses.\n function file(bytes32 what, uint16 centrifugeId, IAdapter[] calldata value) external;\n\n /// @notice Used to update an address ( state variable ) on very rare occasions.\n /// @dev Currently used to update addresses of contract instances.\n /// @param what The name of the variable to be updated.\n /// @param data New address.\n function file(bytes32 what, address data) external;\n\n /// @notice Repay an underpaid batch. Send unused funds to subsidy pot of the pool.\n function repay(uint16 centrifugeId, bytes memory batch) external payable;\n\n /// @notice Retry a failed message.\n function retry(uint16 centrifugeId, bytes memory message) external;\n\n /// @notice Set the refund address for message associated to a poolId\n function setRefundAddress(PoolId poolId, IRecoverable refund) external;\n\n /// @notice Pay upfront to later be able to subsidize messages associated to a pool\n function subsidizePool(PoolId poolId) external payable;\n\n /// @notice Prepays for the TX cost for sending the messages through the adapters\n /// Currently being called from Vault Router only.\n /// In order to prepay, the method MUST be called with `msg.value`.\n /// Called is assumed to have called IGateway.estimate before calling this.\n function payTransaction(address payer) external payable;\n\n /// @notice Initialize batching message\n function startBatching() external;\n\n /// @notice Finalize batching messages and send the resulting batch message\n function endBatching() external;\n\n /// @notice Execute message recovery. After the challenge period, the recovery can be executed.\n /// If a malign adapter initiates message recovery,\n /// governance can dispute and immediately cancel the recovery, using any other valid adapter.\n ///\n /// Only 1 recovery can be outstanding per message hash. If multiple adapters fail at the same time,\n /// these will need to be recovered serially (increasing the challenge period for each failed adapter).\n /// @param centrifugeId Chain where the adapter is configured for\n /// @param adapter Adapter's address that the recovery is targeting\n /// @param message Hash of the message to be recovered\n function executeRecovery(uint16 centrifugeId, IAdapter adapter, bytes calldata message) external;\n\n // --- Helpers ---\n /// @notice A view method of the current quorum.abi\n /// @dev Quorum shows the amount of votes needed in order for a message to be dispatched further.\n /// The quorum is taken from the first adapter which is always the length of active adapters.\n /// @param centrifugeId Chain where the adapter is configured for\n /// return Needed amount\n function quorum(uint16 centrifugeId) external view returns (uint8);\n\n /// @notice Gets the current active routers session id.\n /// @dev When the adapters are updated with new ones,\n /// each new set of adapters has their own sessionId.\n /// Currently it uses sessionId of the previous set and\n /// increments it by 1. The idea of an activeSessionId is\n /// to invalidate any incoming messages from previously used adapters.\n /// @param centrifugeId Chain where the adapter is configured for\n function activeSessionId(uint16 centrifugeId) external view returns (uint64);\n\n /// @notice Counts how many times each incoming messages has been received per adapter.\n /// @dev It supports parallel messages ( duplicates ). That means that the incoming messages could be\n /// the result of two or more independ request from the user of the same type.\n /// i.e. Same user would like to deposit same underlying asset with the same amount more then once.\n /// @param centrifugeId Chain where the adapter is configured for\n /// @param batchHash The hash value of the incoming batch message.\n function votes(uint16 centrifugeId, bytes32 batchHash) external view returns (uint16[MAX_ADAPTER_COUNT] memory);\n\n /// @notice Used to calculate overall cost for bridging a payload on the first adapter and settling\n /// on the destination chain and bridging its payload proofs on n-1 adapter\n /// and settling on the destination chain.\n /// @param payload Used in gas cost calculations.\n /// @dev Currenly the payload is not taken into consideration.\n /// @return total Total cost for sending one message and corresponding proofs on through all adapters\n function estimate(uint16 centrifugeId, bytes calldata payload) external view returns (uint256 total);\n\n /// @notice Returns the address of the adapter at the given id.\n /// @param centrifugeId Chain where the adapter is configured for\n function adapters(uint16 centrifugeId, uint256 id) external view returns (IAdapter);\n\n /// @notice Returns the timestamp when the given recovery can be executed.\n /// @param centrifugeId Chain where the adapter is configured for\n function recoveries(uint16 centrifugeId, IAdapter adapter, bytes32 batchHash)\n external\n view\n returns (uint256 timestamp);\n\n /// @notice Returns the current gateway batching level.\n function isBatching() external view returns (bool);\n}\n" + }, + "src/common/interfaces/IGatewayHandlers.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {D18} from \"src/misc/types/D18.sol\";\n\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {IAdapter} from \"src/common/interfaces/IAdapter.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\n\n/// -----------------------------------------------------\n/// Common Handlers\n/// -----------------------------------------------------\n/// @notice Interface for Gateway methods called by messages\ninterface IGatewayHandler {\n /// @notice Initialize the recovery of a payload.\n /// @param centrifugeId Chain where the adapter is configured for\n /// @param adapter Adapter that the recovery was targeting\n /// @param payloadHash Hash of the payload being disputed\n function initiateRecovery(uint16 centrifugeId, IAdapter adapter, bytes32 payloadHash) external;\n\n /// @notice Cancel the recovery of a payload.\n /// @param centrifugeId Chain where the adapter is configured for\n /// @param adapter Adapter that the recovery was targeting\n /// @param payloadHash Hash of the payload being disputed\n function disputeRecovery(uint16 centrifugeId, IAdapter adapter, bytes32 payloadHash) external;\n}\n\n/// -----------------------------------------------------\n/// CP Handlers\n/// -----------------------------------------------------\n\n/// @notice Interface for CP methods called by messages\ninterface IHubGatewayHandler {\n /// @notice Tells that an asset was already registered in CV, in order to perform the corresponding register.\n function registerAsset(AssetId assetId, uint8 decimals) external;\n\n /// @notice Perform a deposit that was requested from CV.\n function depositRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId depositAssetId, uint128 amount)\n external;\n\n /// @notice Perform a redeem that was requested from CV.\n function redeemRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId payoutAssetId, uint128 amount)\n external;\n\n /// @notice Perform a deposit cancellation that was requested from CV.\n function cancelDepositRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId depositAssetId)\n external;\n\n /// @notice Perform a redeem cancellation that was requested from CV.\n function cancelRedeemRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId payoutAssetId) external;\n\n /// @notice Update a holding by request from CAL.\n function updateHoldingAmount(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n uint128 amount,\n D18 pricePoolPerAsset,\n bool isIncrease\n ) external;\n\n /// @notice Increases the total issuance of shares by request from CAL.\n function increaseShareIssuance(PoolId poolId, ShareClassId scId, uint128 amount) external;\n\n /// @notice Decreases the total issuance of shares by request from CAL.\n function decreaseShareIssuance(PoolId poolId, ShareClassId scId, uint128 amount) external;\n}\n\n/// -----------------------------------------------------\n/// CV Handlers\n/// -----------------------------------------------------\n\n/// @notice Interface for CV methods related to pools called by messages\ninterface IPoolManagerGatewayHandler {\n /// @notice New pool details from an existing Centrifuge pool are added.\n /// @dev The function can only be executed by the gateway contract.\n function addPool(PoolId poolId) external;\n\n /// @notice New share class details from an existing Centrifuge pool are added.\n /// @dev The function can only be executed by the gateway contract.\n function addShareClass(\n PoolId poolId,\n ShareClassId scId,\n string memory tokenName,\n string memory tokenSymbol,\n uint8 decimals,\n bytes32 salt,\n address hook\n ) external;\n\n /// @notice Updates the tokenName and tokenSymbol of a share class token\n /// @dev The function can only be executed by the gateway contract.\n function updateShareMetadata(PoolId poolId, ShareClassId scId, string memory tokenName, string memory tokenSymbol)\n external;\n\n /// @notice Updates the price of a share class token, i.e. the factor of pool currency amount per share class token\n /// @dev The function can only be executed by the gateway contract.\n /// @param poolId The pool id\n /// @param scId The share class id\n /// @param price The price of pool currency per share class token as factor.\n /// @param computedAt The timestamp when the price was computed\n function updatePricePoolPerShare(PoolId poolId, ShareClassId scId, uint128 price, uint64 computedAt) external;\n\n /// @notice Updates the price of an asset, i.e. the factor of pool currency amount per asset unit\n /// @dev The function can only be executed by the gateway contract.\n /// @param poolId The pool id\n /// @param scId The share class id\n /// @param assetId The asset id\n /// @param poolPerAsset The price of pool currency per asset unit as factor.\n /// @param computedAt The timestamp when the price was computed\n function updatePricePoolPerAsset(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n uint128 poolPerAsset,\n uint64 computedAt\n ) external;\n\n /// @notice Updates the hook of a share class token\n /// @param poolId The centrifuge pool id\n /// @param scId The share class id\n /// @param hook The new hook addres\n function updateShareHook(PoolId poolId, ShareClassId scId, address hook) external;\n\n /// @notice Updates the restrictions on a share class token for a specific user\n /// @param poolId The centrifuge pool id\n /// @param scId The share class id\n /// @param update The restriction update in the form of a bytes array indicating\n /// the restriction to be updated, the user to be updated, and a validUntil timestamp.\n function updateRestriction(PoolId poolId, ShareClassId scId, bytes memory update) external;\n\n /// @notice Mints share class tokens to a recipient\n /// @dev The function can only be executed internally or by the gateway contract.\n function handleTransferShares(PoolId poolId, ShareClassId scId, address destinationAddress, uint128 amount)\n external;\n\n /// @notice Updates the target address. Generic update function from CP to CV\n /// @param poolId The centrifuge pool id\n /// @param scId The share class id\n /// @param target The target address to be called\n /// @param update The payload to be processed by the target address\n function updateContract(PoolId poolId, ShareClassId scId, address target, bytes memory update) external;\n}\n\n/// @notice Interface for CV methods related to async investments called by messages\ninterface IRequestManagerGatewayHandler {\n /// @notice Signal from the Hub that an asynchronous investment order has been approved\n ///\n /// @dev This message needs to trigger making the asset amounts available to the pool-share-class.\n function approvedDeposits(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n uint128 assetAmount,\n D18 pricePoolPerAsset\n ) external;\n\n /// @notice Signal from the Hub that an asynchronous investment order has been finalized. Shares have been issued.\n ///\n /// @dev This message needs to trigger minting the new amount of shares.\n function issuedShares(PoolId poolId, ShareClassId scId, uint128 shareAmount, D18 pricePoolPerShare) external;\n\n /// @notice Signal from the Hub that an asynchronous redeem order has been finalized.\n ///\n /// @dev This messages needs to trigger reserving the asset amount for claims of redemptions by users.\n function revokedShares(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n uint128 assetAmount,\n uint128 shareAmount,\n D18 pricePoolPerShare\n ) external;\n\n // --- Deposits ---\n /// @notice Fulfills pending deposit requests after successful epoch execution on CP.\n /// The amount of shares that can be claimed by the user is minted and moved to the escrow contract.\n /// The MaxMint bookkeeping value is updated.\n /// The request fulfillment can be partial.\n /// @dev The shares in the escrow are reserved for the user and are transferred to the user on deposit\n /// and mint calls.\n function fulfillDepositRequest(\n PoolId poolId,\n ShareClassId scId,\n address user,\n AssetId assetId,\n uint128 assets,\n uint128 shares\n ) external;\n\n /// @notice Fulfills deposit request cancellation after successful epoch execution on CP.\n /// The amount of assets that can be claimed by the user is locked in the escrow contract.\n /// Updates claimableCancelDepositRequest bookkeeping value. The cancellation order execution can be\n /// partial.\n /// @dev The assets in the escrow are reserved for the user and are transferred to the user during\n /// claimCancelDepositRequest calls.\n /// `fulfillment` represents the decrease in `pendingDepositRequest`.\n /// This is a separate parameter from `assets` since there can be some precision loss when calculating this,\n /// which would lead to having dust in the pendingDepositRequest value and\n /// never closing out the request even after it is technically fulfilled.\n ///\n /// Example:\n /// User deposits 100 units of the vaults underlying asset.\n /// - At some point they make cancellation request. The order in which is not guaranteed\n /// Both requests arrive at CentrifugeChain. If the cancellation is first then all of the\n /// deposited amount will be cancelled.\n ///\n /// - There is the case where the deposit event is first and it gets completely fulfilled then\n /// No amount of the deposited asset will be cancelled.\n ///\n /// - There is the case where partially the deposit request is fulfilled. Let's say 40 units.\n /// Then the cancel request arrives.\n /// The remaining amount of deposited funds which is 60 units will cancelled.\n /// There is a scenario where the deposit funds might different from the pool currency so some\n /// swapping might happen. Either during this swapping or some fee collection or rounding there will be\n /// difference between the actual amount that will be returned to the user.\n /// `fulfillment` in this case will be 60 units but assets will be some lower amount because of the\n /// aforementioned reasons\n /// Let's assume the `asset` is 59. The user will be able to take back these 59 but\n /// in order to not let any dust, we use `fulfillment` in our calculations.\n ///\n /// `pendingDepositRequest` not necessary gets zeroed during this cancellation event.\n /// When CentrifugeChain process the cancel event on its side, part of the deposit might be fulfilled.\n /// In such case the chain will send two messages, one `fulfillDepositRequest` and one\n /// `fulfillCancelDepositRequest`. In the example above, given the 100 units\n /// deposited, 40 units are fulfilled and 60 can be cancelled.\n /// The two messages sent from CentrifugeChain are not guaranteed to arrive in order.\n ///\n /// Assuming first is the `fulfillCancelDepositRequest` the `pendingDepositRequest` here will be reduced to\n /// 60 units only. Then the `fulfillCancelDepositRequest` arrives with `fulfillment` 60. This amount is\n /// removed from `pendingDepositRequests`. Since there are not more pendingDepositRequest` the\n /// `pendingCancelDepositRequest` gets deleted.\n ///\n /// Assuming first the `fulfillCancelDepositRequest` arrives then the `pendingDepositRequest` will be 100.\n /// `fulfillment` is 60 so we are left with `pendingDepositRequest` equals to 40 ( 100 - 60 ).\n /// Then the second message arrives which is `fulfillDepositRequest`. ( Check `fulfillDepositRequest`\n /// implementation for details.)\n /// When it arrives the `pendingDepositRequest` is 40 and the assets is 40\n /// so there are no more `pendingDepositRequest` and right there the `pendingCancelDepositRequest will be\n /// deleted.\n function fulfillCancelDepositRequest(\n PoolId poolId,\n ShareClassId scId,\n address user,\n AssetId assetId,\n uint128 assets,\n uint128 fulfillment\n ) external;\n\n // --- Redeems ---\n /// @notice Fulfills pending redeem requests after successful epoch execution on CP.\n /// The amount of redeemed shares is burned. The amount of assets that can be claimed by the user in\n /// return is locked in the escrow contract. The MaxWithdraw bookkeeping value is updated.\n /// The request fulfillment can be partial.\n /// @dev The assets in the escrow are reserved for the user and are transferred to the user on redeem\n /// and withdraw calls.\n function fulfillRedeemRequest(\n PoolId poolId,\n ShareClassId scId,\n address user,\n AssetId assetId,\n uint128 assets,\n uint128 shares\n ) external;\n\n /// @notice Fulfills redeem request cancellation after successful epoch execution on CP.\n /// The amount of shares that can be claimed by the user is locked in the escrow contract.\n /// Updates claimableCancelRedeemRequest bookkeeping value. The cancellation order execution can also be\n /// partial.\n /// @dev The shares in the escrow are reserved for the user and are transferred to the user during\n /// claimCancelRedeemRequest calls.\n function fulfillCancelRedeemRequest(PoolId poolId, ShareClassId scId, address user, AssetId assetId, uint128 shares)\n external;\n}\n\n/// @notice Interface for CV methods related to epoch called by messages\ninterface IBalanceSheetGatewayHandler {\n function triggerDeposit(PoolId poolId, ShareClassId scId, AssetId assetId, address provider, uint128 amount)\n external;\n\n function triggerWithdraw(PoolId poolId, ShareClassId scId, AssetId assetId, address receiver, uint128 amount)\n external;\n\n function triggerIssueShares(PoolId poolId, ShareClassId scId, address to, uint128 shares) external;\n\n function submitQueuedShares(PoolId poolId, ShareClassId scId) external;\n\n function submitQueuedAssets(PoolId poolId, ShareClassId scId, AssetId assetId) external;\n\n function setQueue(PoolId poolId, ShareClassId scId, bool enabled) external;\n}\n" + }, + "src/common/interfaces/IGatewaySenders.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {D18} from \"src/misc/types/D18.sol\";\n\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\n\ninterface ILocalCentrifugeId {\n function localCentrifugeId() external view returns (uint16);\n}\n\n/// @notice Interface for dispatch-only gateway\ninterface IRootMessageSender {\n /// @notice Creates and send the message\n function sendScheduleUpgrade(uint16 centrifugeId, bytes32 target) external;\n\n /// @notice Creates and send the message\n function sendCancelUpgrade(uint16 centrifugeId, bytes32 target) external;\n\n /// @notice Creates and send the message\n function sendRecoverTokens(\n uint16 centrifugeId,\n bytes32 target,\n bytes32 token,\n uint256 tokenId,\n bytes32 to,\n uint256 amount\n ) external;\n\n /// @notice Creates and send the message\n function sendInitiateRecovery(uint16 centrifugeId, uint16 adapterCentrifugeId, bytes32 adapter, bytes32 hash)\n external;\n\n /// @notice Creates and send the message\n function sendDisputeRecovery(uint16 centrifugeId, uint16 adapterCentrifugeId, bytes32 adapter, bytes32 hash)\n external;\n}\n\n/// @notice Interface for dispatch-only gateway\ninterface IPoolMessageSender is ILocalCentrifugeId {\n /// @notice Creates and send the message\n function sendNotifyPool(uint16 centrifugeId, PoolId poolId) external;\n\n /// @notice Creates and send the message\n function sendNotifyShareClass(\n uint16 centrifugeId,\n PoolId poolId,\n ShareClassId scId,\n string memory name,\n string memory symbol,\n uint8 decimals,\n bytes32 salt,\n bytes32 hook\n ) external;\n\n /// @notice Creates and send the message\n function sendNotifyShareMetadata(\n uint16 centrifugeId,\n PoolId poolId,\n ShareClassId scId,\n string memory name,\n string memory symbol\n ) external;\n\n /// @notice Creates and send the message\n function sendUpdateShareHook(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bytes32 hook) external;\n\n /// @notice Creates and send the message\n function sendNotifyPricePoolPerShare(uint16 chainId, PoolId poolId, ShareClassId scId, D18 pricePerShare)\n external;\n\n /// @notice Creates and send the message\n function sendNotifyPricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId, D18 pricePerShare)\n external;\n\n /// @notice Creates and send the message\n function sendFulfilledDepositRequest(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n bytes32 investor,\n uint128 assetAmount,\n uint128 shareAmount\n ) external;\n\n /// @notice Creates and send the message\n function sendFulfilledRedeemRequest(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n bytes32 investor,\n uint128 assetAmount,\n uint128 shareAmount\n ) external;\n\n /// @notice Creates and send the message\n function sendFulfilledCancelDepositRequest(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n bytes32 investor,\n uint128 cancelledAmount\n ) external;\n\n /// @notice Creates and send the message\n function sendFulfilledCancelRedeemRequest(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n bytes32 investor,\n uint128 cancelledShares\n ) external;\n\n /// @notice Creates and send the message\n function sendUpdateRestriction(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bytes calldata payload)\n external;\n\n /// @notice Creates and send the message\n function sendUpdateContract(\n uint16 centrifugeId,\n PoolId poolId,\n ShareClassId scId,\n bytes32 target,\n bytes calldata payload\n ) external;\n\n /// @notice Creates and send the message\n function sendApprovedDeposits(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n uint128 assetAmount,\n D18 pricePoolPerAsset\n ) external;\n\n // @notice Creates and send the message\n function sendIssuedShares(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n uint128 shareAmount,\n D18 pricePoolPerShare\n ) external;\n\n /// @notice Creates and send the message\n function sendRevokedShares(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n uint128 assetAmount,\n uint128 shareAmount,\n D18 pricePoolPerShare\n ) external;\n\n /// @notice Creates and send the message\n function sendTriggerIssueShares(uint16 centrifugeId, PoolId poolId, ShareClassId scId, address who, uint128 shares)\n external;\n\n /// @notice Creates and send the message\n function sendTriggerSubmitQueuedShares(uint16 centrifugeId, PoolId poolId, ShareClassId scId) external;\n\n /// @notice Creates and send the message\n function sendTriggerSubmitQueuedAssets(PoolId poolId, ShareClassId scId, AssetId assetId) external;\n\n /// @notice Creates and send the message\n function sendSetQueue(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bool enabled) external;\n}\n\n/// @notice Interface for dispatch-only gateway\ninterface IVaultMessageSender is ILocalCentrifugeId {\n /// @notice Creates and send the message\n function sendTransferShares(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bytes32 receiver, uint128 amount)\n external;\n\n /// @notice Creates and send the message\n function sendDepositRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId assetId, uint128 amount)\n external;\n\n /// @notice Creates and send the message\n function sendRedeemRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId assetId, uint128 amount)\n external;\n\n /// @notice Creates and send the message\n function sendCancelDepositRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId assetId) external;\n\n /// @notice Creates and send the message\n function sendCancelRedeemRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId assetId) external;\n\n /// @notice Creates and send the message\n function sendRegisterAsset(uint16 centrifugeId, AssetId assetId, uint8 decimals) external;\n\n /// @notice Creates and send the message\n function sendUpdateHoldingAmount(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n address provider,\n uint128 amount,\n D18 pricePoolPerAsset,\n bool isIncrease\n ) external;\n\n /// @notice Creates and send the message\n function sendUpdateShares(PoolId poolId, ShareClassId scId, uint128 shares, bool isIssuance) external;\n}\n" + }, + "src/common/interfaces/IGuardian.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {IAdapter} from \"src/common/interfaces/IAdapter.sol\";\n\ninterface ISafe {\n function isOwner(address signer) external view returns (bool);\n}\n\ninterface IGuardian {\n error NotTheAuthorizedSafe();\n error NotTheAuthorizedSafeOrItsOwner();\n\n /// @notice Dispatched when the `what` parameter of `file()` is not supported by the implementation.\n error FileUnrecognizedParam();\n\n /// @notice Emitted when a call to `file()` was performed.\n event File(bytes32 indexed what, address addr);\n\n /// @notice Return the linked Safe\n function safe() external view returns (ISafe);\n\n /// @notice Updates a contract parameter.\n /// @param what Name of the parameter to update.\n /// Accepts a `bytes32` representation of 'sender' string value.\n /// @param data New value given to the `what` parameter\n function file(bytes32 what, address data) external;\n\n /// @notice Registers a new pool\n function createPool(PoolId poolId, address admin, AssetId currency) external;\n\n /// @notice Pause the protocol\n /// @dev callable by both safe and owners\n function pause() external;\n\n /// @notice Unpause the protocol\n /// @dev callable by safe only\n function unpause() external;\n\n /// @notice Schedule relying a target address on Root\n /// @dev callable by safe only\n function scheduleRely(address target) external;\n\n /// @notice Cancel a scheduled rely\n /// @dev callable by safe only\n function cancelRely(address target) external;\n\n /// @notice Schedule an upgrade (scheduled rely) on a specific chain\n /// @dev Only supports EVM targets today\n function scheduleUpgrade(uint16 centrifugeId, address target) external;\n\n /// @notice Cancel an upgrade (scheduled rely) on a specific chain\n /// @dev Only supports EVM targets today\n function cancelUpgrade(uint16 centrifugeId, address target) external;\n\n /// @notice Recover tokens on a specific chain\n /// @dev Only supports EVM targets today\n function recoverTokens(\n uint16 centrifugeId,\n address target,\n address token,\n uint256 tokenId,\n address to,\n uint256 amount\n ) external;\n\n /// @notice Initiate a gateway payload recovery on a specific chain\n /// @dev Only supports EVM targets today\n function initiateRecovery(uint16 centrifugeId, uint16 adapterCentrifugeId, IAdapter adapter, bytes32 hash)\n external;\n\n /// @notice Dispute a gateway paylaod recovery on a specific chain\n /// @dev Only supports EVM targets today\n function disputeRecovery(uint16 centrifugeId, uint16 adapterCentrifugeId, IAdapter adapter, bytes32 hash)\n external;\n}\n" + }, + "src/common/interfaces/IGuardianActions.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\n\ninterface IHubGuardianActions {\n /// @notice Creates a new pool. `msg.sender` will be the admin of the created pool.\n /// @param currency The pool currency. Usually an AssetId identifying by a ISO4217 code.\n function createPool(PoolId poolId, address admin, AssetId currency) external payable;\n}\n" + }, + "src/common/interfaces/IHook.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IERC165} from \"src/misc/interfaces/IERC7575.sol\";\n\nstruct HookData {\n bytes16 from;\n bytes16 to;\n}\n\nuint8 constant SUCCESS_CODE_ID = 0;\nstring constant SUCCESS_MESSAGE = \"transfer-allowed\";\n\nuint8 constant ERROR_CODE_ID = 1;\nstring constant ERROR_MESSAGE = \"transfer-blocked\";\n\n/// @dev Magic address denoting a transfer to the escrow\n/// @dev Solely used for gas saving since escrow is per pool\naddress constant ESCROW_HOOK_ID = address(uint160(uint8(0xce)));\n\n/// @notice Hook interface to customize share token behaviour\n/// @dev To detect specific system actions:\n/// Deposit request: address(0) -> address(user)\n/// Deposit claim: ESCROW_HOOK_ID -> address(user)\n/// Redeem request: address(user) -> ESCROW_HOOK_ID\n/// Redeem claim: address(user) -> address(0)\n/// Cross-chain transfer: address(user) -> address(uint160(chainId))\ninterface IHook is IERC165 {\n // --- Errors ---\n error TransferBlocked();\n error InvalidUpdate();\n\n /// @notice Callback on standard ERC20 transfer.\n /// @dev MUST return bytes4(keccak256(\"onERC20Transfer(address,address,uint256,(bytes16,bytes16))\"))\n /// if successful\n function onERC20Transfer(address from, address to, uint256 value, HookData calldata hookdata)\n external\n returns (bytes4);\n\n /// @notice Callback on authorized ERC20 transfer.\n /// @dev Cannot be blocked, can only be used to update state.\n /// Return value is ignored, only kept for compatibility with V2 share tokens.\n function onERC20AuthTransfer(address sender, address from, address to, uint256 value, HookData calldata hookdata)\n external\n returns (bytes4);\n\n /// @notice Check if given transfer can be performed\n function checkERC20Transfer(address from, address to, uint256 value, HookData calldata hookData)\n external\n view\n returns (bool);\n\n /// @notice Update a set of restriction for a token\n /// @dev MAY be user specific, which would be included in the encoded `update` value\n function updateRestriction(address token, bytes memory update) external;\n}\n" + }, + "src/common/interfaces/IMessageDispatcher.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IVaultMessageSender, IPoolMessageSender, IRootMessageSender} from \"src/common/interfaces/IGatewaySenders.sol\";\n\ninterface IMessageDispatcher is IRootMessageSender, IVaultMessageSender, IPoolMessageSender {\n /// @notice Emitted when a call to `file()` was performed.\n event File(bytes32 indexed what, address addr);\n\n /// @notice Dispatched when the `what` parameter of `file()` is not supported by the implementation.\n error FileUnrecognizedParam();\n\n /// @notice Updates a contract parameter.\n /// @param what Name of the parameter to update.\n /// Accepts a `bytes32` representation of 'hubRegistry' string value.\n /// @param data New value given to the `what` parameter\n function file(bytes32 what, address data) external;\n\n /// @notice Estimate sending a message through the gateway.\n /// If the message is to the same centrifugeId, then the estimation is 0.\n function estimate(uint16 centrifugeId, bytes calldata payload) external view returns (uint256 amount);\n}\n" + }, + "src/common/interfaces/IMessageHandler.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\n/// @notice Generic interface for entities that handle incoming messages\ninterface IMessageHandler {\n /// @notice Dispatched when an invalid message is trying to handle\n error InvalidMessage(uint8 code);\n\n /// @notice Handling incoming messages.\n /// @param centrifugeId Source chain\n /// @param message Incoming message\n function handle(uint16 centrifugeId, bytes calldata message) external;\n}\n" + }, + "src/common/interfaces/IMessageProcessor.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IMessageHandler} from \"src/common/interfaces/IMessageHandler.sol\";\nimport {IMessageProperties} from \"src/common/interfaces/IMessageProperties.sol\";\n\ninterface IMessageProcessor is IMessageHandler, IMessageProperties {\n /// @notice Emitted when a call to `file()` was performed.\n event File(bytes32 indexed what, address addr);\n\n /// @notice Dispatched when the `what` parameter of `file()` is not supported by the implementation.\n error FileUnrecognizedParam();\n\n /// @notice Updates a contract parameter.\n /// @param what Name of the parameter to update.\n /// Accepts a `bytes32` representation of 'hubRegistry' string value.\n /// @param data New value given to the `what` parameter\n function file(bytes32 what, address data) external;\n}\n" + }, + "src/common/interfaces/IMessageProperties.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\n\n/// @notice Defines methods to get properties from raw messages\ninterface IMessageProperties {\n /// @notice Inspect the message to tell if the message is recovery message\n function isMessageRecovery(bytes calldata message) external pure returns (bool);\n\n /// @notice Inspect the message to return the length\n function messageLength(bytes calldata message) external pure returns (uint16);\n\n /// @notice Inspect the message to return the associated PoolId if any\n function messagePoolId(bytes calldata message) external pure returns (PoolId);\n}\n" + }, + "src/common/interfaces/IMessageSender.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\n/// @notice Generic interface for entities that handles outgoing messages\ninterface IMessageSender {\n /// @notice Handling outgoing messages.\n /// @param centrifugeId Destination chain\n function send(uint16 centrifugeId, bytes calldata message) external;\n}\n" + }, + "src/common/interfaces/IRoot.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IMessageHandler} from \"src/common/interfaces/IMessageHandler.sol\";\n\ninterface IRoot {\n // --- Events ---\n event File(bytes32 indexed what, uint256 data);\n event Pause();\n event Unpause();\n event ScheduleRely(address indexed target, uint256 indexed scheduledTime);\n event CancelRely(address indexed target);\n event RelyContract(address indexed target, address indexed user);\n event DenyContract(address indexed target, address indexed user);\n event Endorse(address indexed user);\n event Veto(address indexed user);\n\n error DelayTooLong();\n error FileUnrecognizedParam();\n error TargetNotScheduled();\n error TargetNotReady();\n\n /// @notice Returns whether the root is paused\n function paused() external view returns (bool);\n\n /// @notice Returns the current timelock for adding new wards\n function delay() external view returns (uint256);\n\n /// @notice Trusted contracts within the system\n function endorsements(address target) external view returns (uint256);\n\n /// @notice Returns when `relyTarget` has passed the timelock\n function schedule(address relyTarget) external view returns (uint256 timestamp);\n\n // --- Administration ---\n /// @notice Updates a contract parameter\n /// @param what Accepts a bytes32 representation of 'delay'\n function file(bytes32 what, uint256 data) external;\n\n /// --- Endorsements ---\n /// @notice Endorses the `user`\n /// @dev Endorsed users are trusted contracts in the system. They are allowed to bypass\n /// token restrictions (e.g. the Escrow can automatically receive share class tokens by being endorsed), and\n /// can automatically set operators in ERC-7540 vaults (e.g. the VaultRouter) is always an operator.\n function endorse(address user) external;\n\n /// @notice Removes the endorsed user\n function veto(address user) external;\n\n /// @notice Returns whether the user is endorsed\n function endorsed(address user) external view returns (bool);\n\n // --- Pause management ---\n /// @notice Pause any contracts that depend on `Root.paused()`\n function pause() external;\n\n /// @notice Unpause any contracts that depend on `Root.paused()`\n function unpause() external;\n\n /// --- Timelocked ward management ---\n /// @notice Schedule relying a new ward after the delay has passed\n function scheduleRely(address target) external;\n\n /// @notice Cancel a pending scheduled rely\n function cancelRely(address target) external;\n\n /// @notice Execute a scheduled rely\n /// @dev Can be triggered by anyone since the scheduling is protected\n function executeScheduledRely(address target) external;\n\n /// --- External contract ward management ---\n /// @notice Make an address a ward on any contract that Root is a ward on\n function relyContract(address target, address user) external;\n\n /// @notice Removes an address as a ward on any contract that Root is a ward on\n function denyContract(address target, address user) external;\n}\n" + }, + "src/common/interfaces/ITokenRecoverer.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IRecoverable} from \"src/misc/interfaces/IRecoverable.sol\";\n\ninterface ITokenRecoverer {\n event RecoverTokens(\n IRecoverable indexed target, address indexed token, uint256 tokenId, address indexed to, uint256 amount\n );\n\n function recoverTokens(IRecoverable target, address token, uint256 tokenId, address to, uint256 amount) external;\n}\n" + }, + "src/common/interfaces/IWormholeAdapter.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IAdapter} from \"src/common/interfaces/IAdapter.sol\";\n\n// From https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/interfaces/IWormholeRelayer.sol#L75\ninterface IWormholeRelayer {\n /**\n * @notice Publishes an instruction for the default delivery provider\n * to relay a payload to the address `targetAddress` on chain `targetChain`\n * with gas limit `gasLimit` and `msg.value` equal to `receiverValue`\n *\n * Any refunds (from leftover gas) will be sent to `refundAddress` on chain `refundChain`\n * `targetAddress` must implement the IWormholeReceiver interface\n *\n * This function must be called with `msg.value` equal to `quoteEVMDeliveryPrice(targetChain, receiverValue,\n * gasLimit)`\n *\n * @param targetChain in Wormhole Chain ID format\n * @param targetAddress address to call on targetChain (that implements IWormholeReceiver)\n * @param payload arbitrary bytes to pass in as parameter in call to `targetAddress`\n * @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain\n * currency units)\n * @param gasLimit gas limit with which to call `targetAddress`. Any units of gas unused will be refunded according\n * to the\n * `targetChainRefundPerGasUnused` rate quoted by the delivery provider\n * @param refundChain The chain to deliver any refund to, in Wormhole Chain ID format\n * @param refundAddress The address on `refundChain` to deliver any refund to\n * @return sequence sequence number of published VAA containing delivery instructions\n */\n function sendPayloadToEvm(\n uint16 targetChain,\n address targetAddress,\n bytes memory payload,\n uint256 receiverValue,\n uint256 gasLimit,\n uint16 refundChain,\n address refundAddress\n ) external payable returns (uint64 sequence);\n\n /**\n * @notice Returns the price to request a relay to chain `targetChain`, using the default delivery provider\n *\n * @param targetChain in Wormhole Chain ID format\n * @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain\n * currency units)\n * @param gasLimit gas limit with which to call `targetAddress`.\n * @return nativePriceQuote Price, in units of current chain currency, that the delivery provider charges to perform\n * the relay\n * @return targetChainRefundPerGasUnused amount of target chain currency that will be refunded per unit of gas\n * unused,\n * if a refundAddress is specified.\n * Note: This value can be overridden by the delivery provider on the target chain. The returned value here\n * should be considered to be a\n * promise by the delivery provider of the amount of refund per gas unused that will be returned to the\n * refundAddress at the target chain.\n * If a delivery provider decides to override, this will be visible as part of the emitted Delivery event on\n * the target chain.\n */\n function quoteEVMDeliveryPrice(uint16 targetChain, uint256 receiverValue, uint256 gasLimit)\n external\n view\n returns (uint256 nativePriceQuote, uint256 targetChainRefundPerGasUnused);\n\n /**\n * @notice Returns the address of the current default delivery provider\n * @return deliveryProvider The address of (the default delivery provider)'s contract on this source\n * chain. This must be a contract that implements IDeliveryProvider.\n */\n function getDefaultDeliveryProvider() external view returns (address deliveryProvider);\n}\n\ninterface IWormholeDeliveryProvider {\n /// @notice Returns the chain ID.\n function chainId() external view returns (uint16);\n}\n\n// From\n// https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IWormholeReceiver.sol\ninterface IWormholeReceiver {\n /**\n * @notice When a `send` is performed with this contract as the target, this function will be\n * invoked by the WormholeRelayer contract\n *\n * NOTE: This function should be restricted such that only the Wormhole Relayer contract can call it.\n *\n * We also recommend that this function checks that `sourceChain` and `sourceAddress` are indeed who\n * you expect to have requested the calling of `send` on the source chain\n *\n * The invocation of this function corresponding to the `send` request will have msg.value equal\n * to the receiverValue specified in the send request.\n *\n * If the invocation of this function reverts or exceeds the gas limit\n * specified by the send requester, this delivery will result in a `ReceiverFailure`.\n *\n * @param payload - an arbitrary message which was included in the delivery by the\n * requester. This message's signature will already have been verified (as long as msg.sender is the Wormhole\n * Relayer contract)\n * @param additionalMessages - Additional messages which were requested to be included in this delivery.\n * Note: There are no contract-level guarantees that the messages in this array are what was requested\n * so **you should verify any sensitive information given here!**\n *\n * For example, if a 'VaaKey' was specified on the source chain, then MAKE SURE the corresponding message here\n * has valid signatures (by calling `parseAndVerifyVM(message)` on the Wormhole core contract)\n *\n * This field can be used to perform and relay TokenBridge or CCTP transfers, and there are example\n * usages of this at\n * https://github.com/wormhole-foundation/hello-token\n * https://github.com/wormhole-foundation/hello-cctp\n *\n * @param sourceAddress - the (wormhole format) address on the sending chain which requested\n * this delivery.\n * @param sourceChain - the wormhole chain ID where this delivery was requested.\n * @param deliveryHash - the VAA hash of the deliveryVAA.\n *\n */\n function receiveWormholeMessages(\n bytes memory payload,\n bytes[] memory additionalMessages,\n bytes32 sourceAddress,\n uint16 sourceChain,\n bytes32 deliveryHash\n ) external payable;\n}\n\nstruct WormholeSource {\n uint16 centrifugeId;\n address addr;\n}\n\nstruct WormholeDestination {\n uint16 wormholeId;\n address addr;\n}\n\ninterface IWormholeAdapter is IAdapter, IWormholeReceiver {\n /// @dev see file() method\n event File(bytes32 indexed what, uint16 fromChainId, uint16 toChainId, address addr);\n\n error FileUnrecognizedParam();\n error NotWormholeRelayer();\n error InvalidSource();\n\n /// @dev Configures the adapter\n /// @param what Can be \"sources\" or \"destinations\".\n /// @param addr if what == \"sources\", it represents the source\n /// @param addr if what == \"destinations\", it represents the destination\n function file(bytes32 what, uint16 centrifugeId, uint16 wormholeId, address addr) external;\n}\n" + }, + "src/common/libraries/MessageLib.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\n\nenum MessageType {\n /// @dev Placeholder for null message type\n _Invalid,\n /// @dev Placeholder for proof message type\n _MessageProof,\n // -- Gateway messages\n InitiateRecovery,\n DisputeRecovery,\n // -- Root messages\n ScheduleUpgrade,\n CancelUpgrade,\n RecoverTokens,\n // -- Pool manager messages\n RegisterAsset,\n NotifyPool,\n NotifyShareClass,\n NotifyPricePoolPerShare,\n NotifyPricePoolPerAsset,\n NotifyShareMetadata,\n UpdateShareHook,\n TransferShares,\n UpdateRestriction,\n UpdateContract,\n ApprovedDeposits,\n IssuedShares,\n RevokedShares,\n // -- Investment manager messages\n DepositRequest,\n RedeemRequest,\n FulfilledDepositRequest,\n FulfilledRedeemRequest,\n CancelDepositRequest,\n CancelRedeemRequest,\n FulfilledCancelDepositRequest,\n FulfilledCancelRedeemRequest,\n // -- BalanceSheet messages\n UpdateHoldingAmount,\n UpdateShares,\n TriggerIssueShares,\n TriggerSubmitQueuedShares,\n TriggerSubmitQueuedAssets,\n SetQueue\n}\n\nenum UpdateRestrictionType {\n /// @dev Placeholder for null update restriction type\n Invalid,\n Member,\n Freeze,\n Unfreeze\n}\n\nenum UpdateContractType {\n /// @dev Placeholder for null update restriction type\n Invalid,\n VaultUpdate,\n UpdateManager,\n MaxAssetPriceAge,\n MaxSharePriceAge,\n Valuation,\n SyncDepositMaxReserve\n}\n\n/// @dev Used internally in the VaultUpdateMessage (not represent a submessage)\nenum VaultUpdateKind {\n DeployAndLink,\n Link,\n Unlink\n}\n\nlibrary MessageLib {\n using MessageLib for bytes;\n using BytesLib for bytes;\n using CastLib for *;\n\n error UnknownMessageType();\n\n /// @dev Encode all message lengths in this constant to avoid a large list of if/elseif checks\n /// and reduce generated bytecode.\n /// If the message has some dynamic part, will be added later in `messageLength()`.\n // forgefmt: disable-next-item\n uint256 constant MESSAGE_LENGTHS_1 =\n (67 << uint8(MessageType.InitiateRecovery) * 8) +\n (67 << uint8(MessageType.DisputeRecovery) * 8) +\n (33 << uint8(MessageType.ScheduleUpgrade) * 8) +\n (33 << uint8(MessageType.CancelUpgrade) * 8) +\n (161 << uint8(MessageType.RecoverTokens) * 8) +\n (18 << uint8(MessageType.RegisterAsset) * 8) +\n (9 << uint8(MessageType.NotifyPool) * 8) +\n (250 << uint8(MessageType.NotifyShareClass) * 8) +\n (49 << uint8(MessageType.NotifyPricePoolPerShare) * 8) +\n (65 << uint8(MessageType.NotifyPricePoolPerAsset) * 8) +\n (185 << uint8(MessageType.NotifyShareMetadata) * 8) +\n (57 << uint8(MessageType.UpdateShareHook) * 8) +\n (73 << uint8(MessageType.TransferShares) * 8) +\n (25 << uint8(MessageType.UpdateRestriction) * 8) +\n (57 << uint8(MessageType.UpdateContract) * 8) +\n (73 << uint8(MessageType.ApprovedDeposits) * 8) +\n (57 << uint8(MessageType.IssuedShares) * 8) +\n (89 << uint8(MessageType.RevokedShares) * 8) +\n (89 << uint8(MessageType.DepositRequest) * 8) +\n (89 << uint8(MessageType.RedeemRequest) * 8) +\n (105 << uint8(MessageType.FulfilledDepositRequest) * 8) +\n (105 << uint8(MessageType.FulfilledRedeemRequest) * 8) +\n (73 << uint8(MessageType.CancelDepositRequest) * 8) +\n (73 << uint8(MessageType.CancelRedeemRequest) * 8) +\n (89 << uint8(MessageType.FulfilledCancelDepositRequest) * 8) +\n (89 << uint8(MessageType.FulfilledCancelRedeemRequest) * 8) +\n (114 << uint8(MessageType.UpdateHoldingAmount) * 8) +\n (50 << uint8(MessageType.UpdateShares) * 8) +\n (73 << uint8(MessageType.TriggerIssueShares) * 8) +\n (25 << uint8(MessageType.TriggerSubmitQueuedShares) * 8);\n\n // forgefmt: disable-next-item\n uint256 constant MESSAGE_LENGTHS_2 =\n (41 << (uint8(MessageType.TriggerSubmitQueuedAssets) - 32) * 8) +\n (26 << (uint8(MessageType.SetQueue) - 32) * 8);\n\n function messageType(bytes memory message) internal pure returns (MessageType) {\n return MessageType(message.toUint8(0));\n }\n\n function messageCode(bytes memory message) internal pure returns (uint8) {\n return message.toUint8(0);\n }\n\n function messageLength(bytes memory message) internal pure returns (uint16 length) {\n uint8 kind = message.toUint8(0);\n require(kind <= uint8(type(MessageType).max), UnknownMessageType());\n\n length = (kind <= 31)\n ? uint16(uint8(bytes32(MESSAGE_LENGTHS_1)[31 - kind]))\n : uint16(uint8(bytes32(MESSAGE_LENGTHS_2)[63 - kind]));\n\n // Spetial treatment for messages with dynamic size:\n if (kind == uint8(MessageType.UpdateRestriction)) {\n length += 2 + message.toUint16(length); //payloadLength\n } else if (kind == uint8(MessageType.UpdateContract)) {\n length += 2 + message.toUint16(length); //payloadLength\n }\n }\n\n function messagePoolId(bytes memory message) internal pure returns (PoolId poolId) {\n uint8 kind = message.toUint8(0);\n\n // All messages from NotifyPool to SetQueue contains a PoolId in position 1.\n if (kind >= uint8(MessageType.NotifyPool) && kind <= uint8(MessageType.SetQueue)) {\n return PoolId.wrap(message.toUint64(1));\n } else {\n return PoolId.wrap(0);\n }\n }\n\n function updateRestrictionType(bytes memory message) internal pure returns (UpdateRestrictionType) {\n return UpdateRestrictionType(message.toUint8(0));\n }\n\n function updateContractType(bytes memory message) internal pure returns (UpdateContractType) {\n return UpdateContractType(message.toUint8(0));\n }\n\n //---------------------------------------\n // InitiateRecovery\n //---------------------------------------\n\n struct InitiateRecovery {\n bytes32 hash;\n bytes32 adapter;\n uint16 centrifugeId;\n }\n\n function deserializeInitiateRecovery(bytes memory data) internal pure returns (InitiateRecovery memory) {\n require(messageType(data) == MessageType.InitiateRecovery, UnknownMessageType());\n return InitiateRecovery({hash: data.toBytes32(1), adapter: data.toBytes32(33), centrifugeId: data.toUint16(65)});\n }\n\n function serialize(InitiateRecovery memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.InitiateRecovery, t.hash, t.adapter, t.centrifugeId);\n }\n\n //---------------------------------------\n // DisputeRecovery\n //---------------------------------------\n\n struct DisputeRecovery {\n bytes32 hash;\n bytes32 adapter;\n uint16 centrifugeId;\n }\n\n function deserializeDisputeRecovery(bytes memory data) internal pure returns (DisputeRecovery memory) {\n require(messageType(data) == MessageType.DisputeRecovery, UnknownMessageType());\n return DisputeRecovery({hash: data.toBytes32(1), adapter: data.toBytes32(33), centrifugeId: data.toUint16(65)});\n }\n\n function serialize(DisputeRecovery memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.DisputeRecovery, t.hash, t.adapter, t.centrifugeId);\n }\n\n //---------------------------------------\n // ScheduleUpgrade\n //---------------------------------------\n\n struct ScheduleUpgrade {\n bytes32 target;\n }\n\n function deserializeScheduleUpgrade(bytes memory data) internal pure returns (ScheduleUpgrade memory) {\n require(messageType(data) == MessageType.ScheduleUpgrade, UnknownMessageType());\n return ScheduleUpgrade({target: data.toBytes32(1)});\n }\n\n function serialize(ScheduleUpgrade memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.ScheduleUpgrade, t.target);\n }\n\n //---------------------------------------\n // CancelUpgrade\n //---------------------------------------\n\n struct CancelUpgrade {\n bytes32 target;\n }\n\n function deserializeCancelUpgrade(bytes memory data) internal pure returns (CancelUpgrade memory) {\n require(messageType(data) == MessageType.CancelUpgrade, UnknownMessageType());\n return CancelUpgrade({target: data.toBytes32(1)});\n }\n\n function serialize(CancelUpgrade memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.CancelUpgrade, t.target);\n }\n\n //---------------------------------------\n // RecoverTokens\n //---------------------------------------\n\n struct RecoverTokens {\n bytes32 target;\n bytes32 token;\n uint256 tokenId;\n bytes32 to;\n uint256 amount;\n }\n\n function deserializeRecoverTokens(bytes memory data) internal pure returns (RecoverTokens memory) {\n require(messageType(data) == MessageType.RecoverTokens, UnknownMessageType());\n return RecoverTokens({\n target: data.toBytes32(1),\n token: data.toBytes32(33),\n tokenId: data.toUint256(65),\n to: data.toBytes32(97),\n amount: data.toUint256(129)\n });\n }\n\n function serialize(RecoverTokens memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.RecoverTokens, t.target, t.token, t.tokenId, t.to, t.amount);\n }\n\n //---------------------------------------\n // RegisterAsset\n //---------------------------------------\n\n struct RegisterAsset {\n uint128 assetId;\n uint8 decimals;\n }\n\n function deserializeRegisterAsset(bytes memory data) internal pure returns (RegisterAsset memory) {\n require(messageType(data) == MessageType.RegisterAsset, UnknownMessageType());\n return RegisterAsset({assetId: data.toUint128(1), decimals: data.toUint8(17)});\n }\n\n function serialize(RegisterAsset memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.RegisterAsset, t.assetId, t.decimals);\n }\n\n //---------------------------------------\n // NotifyPool\n //---------------------------------------\n\n struct NotifyPool {\n uint64 poolId;\n }\n\n function deserializeNotifyPool(bytes memory data) internal pure returns (NotifyPool memory) {\n require(messageType(data) == MessageType.NotifyPool, UnknownMessageType());\n return NotifyPool({poolId: data.toUint64(1)});\n }\n\n function serialize(NotifyPool memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.NotifyPool, t.poolId);\n }\n\n //---------------------------------------\n // NotifyShareClass\n //---------------------------------------\n\n struct NotifyShareClass {\n uint64 poolId;\n bytes16 scId;\n string name; // Fixed to 128 bytes\n bytes32 symbol; // utf8\n uint8 decimals;\n bytes32 salt;\n bytes32 hook;\n }\n\n function deserializeNotifyShareClass(bytes memory data) internal pure returns (NotifyShareClass memory) {\n require(messageType(data) == MessageType.NotifyShareClass, UnknownMessageType());\n return NotifyShareClass({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n name: data.slice(25, 128).bytes128ToString(),\n symbol: data.toBytes32(153),\n decimals: data.toUint8(185),\n salt: data.toBytes32(186),\n hook: data.toBytes32(218)\n });\n }\n\n function serialize(NotifyShareClass memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(\n MessageType.NotifyShareClass,\n t.poolId,\n t.scId,\n bytes(t.name).sliceZeroPadded(0, 128),\n t.symbol,\n t.decimals,\n t.salt,\n t.hook\n );\n }\n\n //---------------------------------------\n // NotifyPricePoolPerShare\n //---------------------------------------\n\n struct NotifyPricePoolPerShare {\n uint64 poolId;\n bytes16 scId;\n uint128 price;\n uint64 timestamp;\n }\n\n function deserializeNotifyPricePoolPerShare(bytes memory data)\n internal\n pure\n returns (NotifyPricePoolPerShare memory)\n {\n require(messageType(data) == MessageType.NotifyPricePoolPerShare, UnknownMessageType());\n return NotifyPricePoolPerShare({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n price: data.toUint128(25),\n timestamp: data.toUint64(41)\n });\n }\n\n function serialize(NotifyPricePoolPerShare memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.NotifyPricePoolPerShare, t.poolId, t.scId, t.price, t.timestamp);\n }\n\n //---------------------------------------\n // NotifyPricePoolPerAsset\n //---------------------------------------\n\n struct NotifyPricePoolPerAsset {\n uint64 poolId;\n bytes16 scId;\n uint128 assetId;\n uint128 price;\n uint64 timestamp;\n }\n\n function deserializeNotifyPricePoolPerAsset(bytes memory data)\n internal\n pure\n returns (NotifyPricePoolPerAsset memory)\n {\n require(messageType(data) == MessageType.NotifyPricePoolPerAsset, UnknownMessageType());\n return NotifyPricePoolPerAsset({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n assetId: data.toUint128(25),\n price: data.toUint128(41),\n timestamp: data.toUint64(57)\n });\n }\n\n function serialize(NotifyPricePoolPerAsset memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.NotifyPricePoolPerAsset, t.poolId, t.scId, t.assetId, t.price, t.timestamp);\n }\n\n //---------------------------------------\n // NotifyShareMetadata\n //---------------------------------------\n\n struct NotifyShareMetadata {\n uint64 poolId;\n bytes16 scId;\n string name; // Fixed to 128 bytes\n bytes32 symbol; // utf8\n }\n\n function deserializeNotifyShareMetadata(bytes memory data) internal pure returns (NotifyShareMetadata memory) {\n require(messageType(data) == MessageType.NotifyShareMetadata, UnknownMessageType());\n return NotifyShareMetadata({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n name: data.slice(25, 128).bytes128ToString(),\n symbol: data.toBytes32(153)\n });\n }\n\n function serialize(NotifyShareMetadata memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(\n MessageType.NotifyShareMetadata, t.poolId, t.scId, bytes(t.name).sliceZeroPadded(0, 128), t.symbol\n );\n }\n\n //---------------------------------------\n // UpdateShareHook\n //---------------------------------------\n\n struct UpdateShareHook {\n uint64 poolId;\n bytes16 scId;\n bytes32 hook;\n }\n\n function deserializeUpdateShareHook(bytes memory data) internal pure returns (UpdateShareHook memory) {\n require(messageType(data) == MessageType.UpdateShareHook, UnknownMessageType());\n return UpdateShareHook({poolId: data.toUint64(1), scId: data.toBytes16(9), hook: data.toBytes32(25)});\n }\n\n function serialize(UpdateShareHook memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.UpdateShareHook, t.poolId, t.scId, t.hook);\n }\n\n //---------------------------------------\n // TransferShares\n //---------------------------------------\n\n struct TransferShares {\n uint64 poolId;\n bytes16 scId;\n bytes32 receiver;\n uint128 amount;\n }\n\n function deserializeTransferShares(bytes memory data) internal pure returns (TransferShares memory) {\n require(messageType(data) == MessageType.TransferShares, UnknownMessageType());\n return TransferShares({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n receiver: data.toBytes32(25),\n amount: data.toUint128(57)\n });\n }\n\n function serialize(TransferShares memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.TransferShares, t.poolId, t.scId, t.receiver, t.amount);\n }\n\n //---------------------------------------\n // UpdateRestriction\n //---------------------------------------\n\n struct UpdateRestriction {\n uint64 poolId;\n bytes16 scId;\n bytes payload; // As sequence of bytes\n }\n\n function deserializeUpdateRestriction(bytes memory data) internal pure returns (UpdateRestriction memory) {\n require(messageType(data) == MessageType.UpdateRestriction, UnknownMessageType());\n\n uint16 payloadLength = data.toUint16(25);\n return UpdateRestriction({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n payload: data.slice(27, payloadLength)\n });\n }\n\n function serialize(UpdateRestriction memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.UpdateRestriction, t.poolId, t.scId, uint16(t.payload.length), t.payload);\n }\n\n //---------------------------------------\n // UpdateRestrictionMember (submsg)\n //---------------------------------------\n\n struct UpdateRestrictionMember {\n bytes32 user;\n uint64 validUntil;\n }\n\n function deserializeUpdateRestrictionMember(bytes memory data)\n internal\n pure\n returns (UpdateRestrictionMember memory)\n {\n require(updateRestrictionType(data) == UpdateRestrictionType.Member, UnknownMessageType());\n\n return UpdateRestrictionMember({user: data.toBytes32(1), validUntil: data.toUint64(33)});\n }\n\n function serialize(UpdateRestrictionMember memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(UpdateRestrictionType.Member, t.user, t.validUntil);\n }\n\n //---------------------------------------\n // UpdateRestrictionFreeze (submsg)\n //---------------------------------------\n\n struct UpdateRestrictionFreeze {\n bytes32 user;\n }\n\n function deserializeUpdateRestrictionFreeze(bytes memory data)\n internal\n pure\n returns (UpdateRestrictionFreeze memory)\n {\n require(updateRestrictionType(data) == UpdateRestrictionType.Freeze, UnknownMessageType());\n\n return UpdateRestrictionFreeze({user: data.toBytes32(1)});\n }\n\n function serialize(UpdateRestrictionFreeze memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(UpdateRestrictionType.Freeze, t.user);\n }\n\n //---------------------------------------\n // UpdateRestrictionUnfreeze (submsg)\n //---------------------------------------\n\n struct UpdateRestrictionUnfreeze {\n bytes32 user;\n }\n\n function deserializeUpdateRestrictionUnfreeze(bytes memory data)\n internal\n pure\n returns (UpdateRestrictionUnfreeze memory)\n {\n require(updateRestrictionType(data) == UpdateRestrictionType.Unfreeze, UnknownMessageType());\n\n return UpdateRestrictionUnfreeze({user: data.toBytes32(1)});\n }\n\n function serialize(UpdateRestrictionUnfreeze memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(UpdateRestrictionType.Unfreeze, t.user);\n }\n\n //---------------------------------------\n // UpdateContract\n //---------------------------------------\n\n struct UpdateContract {\n uint64 poolId;\n bytes16 scId;\n bytes32 target;\n bytes payload; // As sequence of bytes\n }\n\n function deserializeUpdateContract(bytes memory data) internal pure returns (UpdateContract memory) {\n require(messageType(data) == MessageType.UpdateContract, UnknownMessageType());\n uint16 payloadLength = data.toUint16(57);\n return UpdateContract({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n target: data.toBytes32(25),\n payload: data.slice(59, payloadLength)\n });\n }\n\n function serialize(UpdateContract memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(\n MessageType.UpdateContract, t.poolId, t.scId, t.target, uint16(t.payload.length), t.payload\n );\n }\n\n //---------------------------------------\n // UpdateContract.VaultUpdate (submsg)\n //---------------------------------------\n\n struct UpdateContractVaultUpdate {\n bytes32 vaultOrFactory;\n uint128 assetId;\n uint8 kind;\n }\n\n function deserializeUpdateContractVaultUpdate(bytes memory data)\n internal\n pure\n returns (UpdateContractVaultUpdate memory)\n {\n require(updateContractType(data) == UpdateContractType.VaultUpdate, UnknownMessageType());\n\n return UpdateContractVaultUpdate({\n vaultOrFactory: data.toBytes32(1),\n assetId: data.toUint128(33),\n kind: data.toUint8(49)\n });\n }\n\n function serialize(UpdateContractVaultUpdate memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(UpdateContractType.VaultUpdate, t.vaultOrFactory, t.assetId, t.kind);\n }\n\n //---------------------------------------\n // UpdateContract.UpdateManager (submsg)\n //---------------------------------------\n\n struct UpdateContractUpdateManager {\n bytes32 who;\n bool canManage;\n }\n\n function deserializeUpdateContractUpdateManager(bytes memory data)\n internal\n pure\n returns (UpdateContractUpdateManager memory)\n {\n require(updateContractType(data) == UpdateContractType.UpdateManager, UnknownMessageType());\n\n return UpdateContractUpdateManager({who: data.toBytes32(1), canManage: data.toBool(33)});\n }\n\n function serialize(UpdateContractUpdateManager memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(UpdateContractType.UpdateManager, t.who, t.canManage);\n }\n\n //---------------------------------------\n // UpdateContract.MaxAssetPriceAge (submsg)\n //---------------------------------------\n\n struct UpdateContractMaxAssetPriceAge {\n uint128 assetId;\n uint64 maxPriceAge;\n }\n\n function deserializeUpdateContractMaxAssetPriceAge(bytes memory data)\n internal\n pure\n returns (UpdateContractMaxAssetPriceAge memory)\n {\n require(updateContractType(data) == UpdateContractType.MaxAssetPriceAge, UnknownMessageType());\n\n return UpdateContractMaxAssetPriceAge({assetId: data.toUint128(1), maxPriceAge: data.toUint64(17)});\n }\n\n function serialize(UpdateContractMaxAssetPriceAge memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(UpdateContractType.MaxAssetPriceAge, t.assetId, t.maxPriceAge);\n }\n\n //---------------------------------------\n // UpdateContract.MaxSharePriceAge (submsg)\n //---------------------------------------\n\n struct UpdateContractMaxSharePriceAge {\n uint64 maxPriceAge;\n }\n\n function deserializeUpdateContractMaxSharePriceAge(bytes memory data)\n internal\n pure\n returns (UpdateContractMaxSharePriceAge memory)\n {\n require(updateContractType(data) == UpdateContractType.MaxSharePriceAge, UnknownMessageType());\n\n return UpdateContractMaxSharePriceAge({maxPriceAge: data.toUint64(1)});\n }\n\n function serialize(UpdateContractMaxSharePriceAge memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(UpdateContractType.MaxSharePriceAge, t.maxPriceAge);\n }\n\n //---------------------------------------\n // UpdateContract.Valuation (submsg)\n //---------------------------------------\n\n struct UpdateContractValuation {\n bytes32 valuation;\n }\n\n function deserializeUpdateContractValuation(bytes memory data)\n internal\n pure\n returns (UpdateContractValuation memory)\n {\n require(updateContractType(data) == UpdateContractType.Valuation, UnknownMessageType());\n\n return UpdateContractValuation({valuation: data.toBytes32(1)});\n }\n\n function serialize(UpdateContractValuation memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(UpdateContractType.Valuation, t.valuation);\n }\n\n //---------------------------------------\n // UpdateContract.SyncDepositMaxReserve (submsg)\n //---------------------------------------\n\n struct UpdateContractSyncDepositMaxReserve {\n uint128 assetId;\n uint128 maxReserve;\n }\n\n function deserializeUpdateContractSyncDepositMaxReserve(bytes memory data)\n internal\n pure\n returns (UpdateContractSyncDepositMaxReserve memory)\n {\n require(updateContractType(data) == UpdateContractType.SyncDepositMaxReserve, UnknownMessageType());\n\n return UpdateContractSyncDepositMaxReserve({assetId: data.toUint128(1), maxReserve: data.toUint128(17)});\n }\n\n function serialize(UpdateContractSyncDepositMaxReserve memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(UpdateContractType.SyncDepositMaxReserve, t.assetId, t.maxReserve);\n }\n\n //---------------------------------------\n // DepositRequest\n //---------------------------------------\n\n struct DepositRequest {\n uint64 poolId;\n bytes16 scId;\n bytes32 investor;\n uint128 assetId;\n uint128 amount;\n }\n\n function deserializeDepositRequest(bytes memory data) internal pure returns (DepositRequest memory) {\n require(messageType(data) == MessageType.DepositRequest, UnknownMessageType());\n return DepositRequest({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n investor: data.toBytes32(25),\n assetId: data.toUint128(57),\n amount: data.toUint128(73)\n });\n }\n\n function serialize(DepositRequest memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.DepositRequest, t.poolId, t.scId, t.investor, t.assetId, t.amount);\n }\n\n //---------------------------------------\n // RedeemRequest\n //---------------------------------------\n\n struct RedeemRequest {\n uint64 poolId;\n bytes16 scId;\n bytes32 investor;\n uint128 assetId;\n uint128 amount;\n }\n\n function deserializeRedeemRequest(bytes memory data) internal pure returns (RedeemRequest memory) {\n require(messageType(data) == MessageType.RedeemRequest, UnknownMessageType());\n return RedeemRequest({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n investor: data.toBytes32(25),\n assetId: data.toUint128(57),\n amount: data.toUint128(73)\n });\n }\n\n function serialize(RedeemRequest memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.RedeemRequest, t.poolId, t.scId, t.investor, t.assetId, t.amount);\n }\n\n //---------------------------------------\n // CancelDepositRequest\n //---------------------------------------\n\n struct CancelDepositRequest {\n uint64 poolId;\n bytes16 scId;\n bytes32 investor;\n uint128 assetId;\n }\n\n function deserializeCancelDepositRequest(bytes memory data) internal pure returns (CancelDepositRequest memory) {\n require(messageType(data) == MessageType.CancelDepositRequest, UnknownMessageType());\n return CancelDepositRequest({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n investor: data.toBytes32(25),\n assetId: data.toUint128(57)\n });\n }\n\n function serialize(CancelDepositRequest memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.CancelDepositRequest, t.poolId, t.scId, t.investor, t.assetId);\n }\n\n //---------------------------------------\n // CancelRedeemRequest\n //---------------------------------------\n\n struct CancelRedeemRequest {\n uint64 poolId;\n bytes16 scId;\n bytes32 investor;\n uint128 assetId;\n }\n\n function deserializeCancelRedeemRequest(bytes memory data) internal pure returns (CancelRedeemRequest memory) {\n require(messageType(data) == MessageType.CancelRedeemRequest, UnknownMessageType());\n return CancelRedeemRequest({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n investor: data.toBytes32(25),\n assetId: data.toUint128(57)\n });\n }\n\n function serialize(CancelRedeemRequest memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.CancelRedeemRequest, t.poolId, t.scId, t.investor, t.assetId);\n }\n\n //---------------------------------------\n // FulfilledDepositRequest\n //---------------------------------------\n\n struct FulfilledDepositRequest {\n uint64 poolId;\n bytes16 scId;\n bytes32 investor;\n uint128 assetId;\n uint128 assetAmount;\n uint128 shareAmount;\n }\n\n function deserializeFulfilledDepositRequest(bytes memory data)\n internal\n pure\n returns (FulfilledDepositRequest memory)\n {\n require(messageType(data) == MessageType.FulfilledDepositRequest, UnknownMessageType());\n return FulfilledDepositRequest({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n investor: data.toBytes32(25),\n assetId: data.toUint128(57),\n assetAmount: data.toUint128(73),\n shareAmount: data.toUint128(89)\n });\n }\n\n function serialize(FulfilledDepositRequest memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(\n MessageType.FulfilledDepositRequest, t.poolId, t.scId, t.investor, t.assetId, t.assetAmount, t.shareAmount\n );\n }\n\n //---------------------------------------\n // FulfilledRedeemRequest\n //---------------------------------------\n\n struct FulfilledRedeemRequest {\n uint64 poolId;\n bytes16 scId;\n bytes32 investor;\n uint128 assetId;\n uint128 assetAmount;\n uint128 shareAmount;\n }\n\n function deserializeFulfilledRedeemRequest(bytes memory data)\n internal\n pure\n returns (FulfilledRedeemRequest memory)\n {\n require(messageType(data) == MessageType.FulfilledRedeemRequest, UnknownMessageType());\n return FulfilledRedeemRequest({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n investor: data.toBytes32(25),\n assetId: data.toUint128(57),\n assetAmount: data.toUint128(73),\n shareAmount: data.toUint128(89)\n });\n }\n\n function serialize(FulfilledRedeemRequest memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(\n MessageType.FulfilledRedeemRequest, t.poolId, t.scId, t.investor, t.assetId, t.assetAmount, t.shareAmount\n );\n }\n\n //---------------------------------------\n // FulfilledCancelDepositRequest\n //---------------------------------------\n\n struct FulfilledCancelDepositRequest {\n uint64 poolId;\n bytes16 scId;\n bytes32 investor;\n uint128 assetId;\n uint128 cancelledAmount;\n }\n\n function deserializeFulfilledCancelDepositRequest(bytes memory data)\n internal\n pure\n returns (FulfilledCancelDepositRequest memory)\n {\n require(messageType(data) == MessageType.FulfilledCancelDepositRequest, UnknownMessageType());\n return FulfilledCancelDepositRequest({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n investor: data.toBytes32(25),\n assetId: data.toUint128(57),\n cancelledAmount: data.toUint128(73)\n });\n }\n\n function serialize(FulfilledCancelDepositRequest memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(\n MessageType.FulfilledCancelDepositRequest, t.poolId, t.scId, t.investor, t.assetId, t.cancelledAmount\n );\n }\n\n //---------------------------------------\n // FulfilledCancelRedeemRequest\n //---------------------------------------\n\n struct FulfilledCancelRedeemRequest {\n uint64 poolId;\n bytes16 scId;\n bytes32 investor;\n uint128 assetId;\n uint128 cancelledShares;\n }\n\n function deserializeFulfilledCancelRedeemRequest(bytes memory data)\n internal\n pure\n returns (FulfilledCancelRedeemRequest memory)\n {\n require(messageType(data) == MessageType.FulfilledCancelRedeemRequest, UnknownMessageType());\n return FulfilledCancelRedeemRequest({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n investor: data.toBytes32(25),\n assetId: data.toUint128(57),\n cancelledShares: data.toUint128(73)\n });\n }\n\n function serialize(FulfilledCancelRedeemRequest memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(\n MessageType.FulfilledCancelRedeemRequest, t.poolId, t.scId, t.investor, t.assetId, t.cancelledShares\n );\n }\n\n //---------------------------------------\n // UpdateHoldingAmount\n //---------------------------------------\n\n struct UpdateHoldingAmount {\n uint64 poolId;\n bytes16 scId;\n uint128 assetId;\n bytes32 who;\n uint128 amount;\n uint128 pricePerUnit;\n uint64 timestamp;\n bool isIncrease; // Signals whether this is an increase or a decrease\n }\n\n function deserializeUpdateHoldingAmount(bytes memory data) internal pure returns (UpdateHoldingAmount memory h) {\n require(messageType(data) == MessageType.UpdateHoldingAmount, \"UnknownMessageType\");\n\n return UpdateHoldingAmount({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n assetId: data.toUint128(25),\n who: data.toBytes32(41),\n amount: data.toUint128(73),\n pricePerUnit: data.toUint128(89),\n timestamp: data.toUint64(105),\n isIncrease: data.toBool(113)\n });\n }\n\n function serialize(UpdateHoldingAmount memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(\n MessageType.UpdateHoldingAmount,\n t.poolId,\n t.scId,\n t.assetId,\n t.who,\n t.amount,\n t.pricePerUnit,\n t.timestamp,\n t.isIncrease\n );\n }\n\n //---------------------------------------\n // UpdateShares\n //---------------------------------------\n\n struct UpdateShares {\n uint64 poolId;\n bytes16 scId;\n uint128 shares;\n uint64 timestamp;\n bool isIssuance;\n }\n\n function deserializeUpdateShares(bytes memory data) internal pure returns (UpdateShares memory) {\n require(messageType(data) == MessageType.UpdateShares, UnknownMessageType());\n\n return UpdateShares({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n shares: data.toUint128(25),\n timestamp: data.toUint64(41),\n isIssuance: data.toBool(49)\n });\n }\n\n function serialize(UpdateShares memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.UpdateShares, t.poolId, t.scId, t.shares, t.timestamp, t.isIssuance);\n }\n\n //---------------------------------------\n // ApprovedDeposits\n //---------------------------------------\n\n struct ApprovedDeposits {\n uint64 poolId;\n bytes16 scId;\n uint128 assetId;\n uint128 assetAmount;\n uint128 pricePoolPerAsset;\n }\n\n function deserializeApprovedDeposits(bytes memory data) internal pure returns (ApprovedDeposits memory) {\n require(messageType(data) == MessageType.ApprovedDeposits, UnknownMessageType());\n\n return ApprovedDeposits({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n assetId: data.toUint128(25),\n assetAmount: data.toUint128(41),\n pricePoolPerAsset: data.toUint128(57)\n });\n }\n\n function serialize(ApprovedDeposits memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(\n MessageType.ApprovedDeposits, t.poolId, t.scId, t.assetId, t.assetAmount, t.pricePoolPerAsset\n );\n }\n\n //---------------------------------------\n // IssuedShares\n //---------------------------------------\n\n struct IssuedShares {\n uint64 poolId;\n bytes16 scId;\n uint128 shareAmount;\n uint128 pricePoolPerShare;\n }\n\n function deserializeIssuedShares(bytes memory data) internal pure returns (IssuedShares memory) {\n require(messageType(data) == MessageType.IssuedShares, UnknownMessageType());\n\n return IssuedShares({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n shareAmount: data.toUint128(25),\n pricePoolPerShare: data.toUint128(41)\n });\n }\n\n function serialize(IssuedShares memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.IssuedShares, t.poolId, t.scId, t.shareAmount, t.pricePoolPerShare);\n }\n\n //---------------------------------------\n // RevokedShares\n //---------------------------------------\n\n struct RevokedShares {\n uint64 poolId;\n bytes16 scId;\n uint128 assetId;\n uint128 shareAmount;\n uint128 pricePoolPerShare;\n uint128 assetAmount;\n }\n\n function deserializeRevokedShares(bytes memory data) internal pure returns (RevokedShares memory) {\n require(messageType(data) == MessageType.RevokedShares, UnknownMessageType());\n\n return RevokedShares({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n assetId: data.toUint128(25),\n assetAmount: data.toUint128(41),\n shareAmount: data.toUint128(57),\n pricePoolPerShare: data.toUint128(73)\n });\n }\n\n function serialize(RevokedShares memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(\n MessageType.RevokedShares, t.poolId, t.scId, t.assetId, t.assetAmount, t.shareAmount, t.pricePoolPerShare\n );\n }\n\n //---------------------------------------\n // TriggerIssueShares\n //---------------------------------------\n\n struct TriggerIssueShares {\n uint64 poolId;\n bytes16 scId;\n bytes32 who;\n uint128 shares;\n }\n\n function deserializeTriggerIssueShares(bytes memory data) internal pure returns (TriggerIssueShares memory) {\n require(messageType(data) == MessageType.TriggerIssueShares, UnknownMessageType());\n\n return TriggerIssueShares({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n who: data.toBytes32(25),\n shares: data.toUint128(57)\n });\n }\n\n function serialize(TriggerIssueShares memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.TriggerIssueShares, t.poolId, t.scId, t.who, t.shares);\n }\n\n //---------------------------------------\n // TriggerSubmitQueuedShares\n //---------------------------------------\n\n struct TriggerSubmitQueuedShares {\n uint64 poolId;\n bytes16 scId;\n }\n\n function deserializeTriggerSubmitQueuedShares(bytes memory data)\n internal\n pure\n returns (TriggerSubmitQueuedShares memory)\n {\n require(messageType(data) == MessageType.TriggerSubmitQueuedShares, UnknownMessageType());\n return TriggerSubmitQueuedShares({poolId: data.toUint64(1), scId: data.toBytes16(9)});\n }\n\n function serialize(TriggerSubmitQueuedShares memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.TriggerSubmitQueuedShares, t.poolId, t.scId);\n }\n\n //---------------------------------------\n // TriggerSubmitQueuedAssets\n //---------------------------------------\n\n struct TriggerSubmitQueuedAssets {\n uint64 poolId;\n bytes16 scId;\n uint128 assetId;\n }\n\n function deserializeTriggerSubmitQueuedAssets(bytes memory data)\n internal\n pure\n returns (TriggerSubmitQueuedAssets memory)\n {\n require(messageType(data) == MessageType.TriggerSubmitQueuedAssets, UnknownMessageType());\n return\n TriggerSubmitQueuedAssets({poolId: data.toUint64(1), scId: data.toBytes16(9), assetId: data.toUint128(25)});\n }\n\n function serialize(TriggerSubmitQueuedAssets memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.TriggerSubmitQueuedAssets, t.poolId, t.scId, t.assetId);\n }\n\n //---------------------------------------\n // SetQueue\n //---------------------------------------\n\n struct SetQueue {\n uint64 poolId;\n bytes16 scId;\n bool enabled;\n }\n\n function deserializeSetQueue(bytes memory data) internal pure returns (SetQueue memory) {\n require(messageType(data) == MessageType.SetQueue, UnknownMessageType());\n return SetQueue({poolId: data.toUint64(1), scId: data.toBytes16(9), enabled: data.toBool(25)});\n }\n\n function serialize(SetQueue memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.SetQueue, t.poolId, t.scId, t.enabled);\n }\n}\n" + }, + "src/common/libraries/MessageProofLib.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\n\nlibrary MessageProofLib {\n using BytesLib for bytes;\n\n uint8 constant MESSAGE_PROOF_ID = 1;\n\n error UnknownMessageProofType();\n\n function deserializeMessageProof(bytes memory data) internal pure returns (bytes32) {\n require(data.toUint8(0) == MESSAGE_PROOF_ID, UnknownMessageProofType());\n return data.toBytes32(1);\n }\n\n function serializeMessageProof(bytes32 hash) internal pure returns (bytes memory) {\n return abi.encodePacked(MESSAGE_PROOF_ID, hash);\n }\n}\n" + }, + "src/common/libraries/PricingLib.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {IERC20Metadata} from \"src/misc/interfaces/IERC20.sol\";\nimport {IERC6909MetadataExt} from \"src/misc/interfaces/IERC6909.sol\";\nimport {D18, d18} from \"src/misc/types/D18.sol\";\n\nimport {PricingLib} from \"src/common/libraries/PricingLib.sol\";\n\nlibrary PricingLib {\n using MathLib for *;\n\n /// @dev Prices are fixed-point integers with 18 decimals\n uint8 internal constant PRICE_DECIMALS = 18;\n\n /// -----------------------------------------------------\n /// View Methods\n /// -----------------------------------------------------\n\n /// @dev Converts the given asset amount to share amount. Returned value is in share decimals.\n ///\n /// @dev NOTE: MUST ONLY be used in AsyncRequestManager which rely on priceAssetPerShare that is derived from\n /// Fulfilled*\n /// message amounts. Any other codepath must use the variant with pricePoolPerAsset and pricePoolPerShare\n function assetToShareAmount(\n address shareToken,\n address asset,\n uint256 tokenId,\n uint128 assetAmount,\n D18 priceAssetPerShare_,\n MathLib.Rounding rounding\n ) internal view returns (uint128 shares) {\n if (assetAmount == 0 || priceAssetPerShare_.raw() == 0) {\n return 0;\n }\n\n uint8 assetDecimals = getAssetDecimals(asset, tokenId);\n uint8 shareDecimals = IERC20Metadata(shareToken).decimals();\n\n return PricingLib.convertWithReciprocalPrice(\n assetAmount, assetDecimals, shareDecimals, priceAssetPerShare_, rounding\n ).toUint128();\n }\n\n /// @dev Converts the given asset amount to share amount. Returned value is in share decimals.\n function assetToShareAmount(\n address shareToken,\n address asset,\n uint256 tokenId,\n uint128 assetAmount,\n D18 pricePoolPerAsset,\n D18 pricePoolPerShare,\n MathLib.Rounding rounding\n ) internal view returns (uint128 shares) {\n if (assetAmount == 0 || pricePoolPerShare.raw() == 0 || pricePoolPerAsset.raw() == 0) {\n return 0;\n }\n\n uint8 assetDecimals = getAssetDecimals(asset, tokenId);\n uint8 shareDecimals = IERC20Metadata(shareToken).decimals();\n\n return PricingLib.assetToShareAmount(\n assetAmount, assetDecimals, shareDecimals, pricePoolPerAsset, pricePoolPerShare, rounding\n ).toUint128();\n }\n\n /// @dev Converts the given share amount to asset amount. Returned value is in share decimals.\n ///\n /// @dev NOTE: MUST ONLY be used in AsyncRequestManager which rely on priceAssetPerShare that is derived from\n /// Fulfilled*\n /// message amounts. Any other codepath must use the variant with pricePoolPerAsset and pricePoolPerShare\n function shareToAssetAmount(\n address shareToken,\n uint128 shareAmount,\n address asset,\n uint256 tokenId,\n D18 priceAssetPerShare_,\n MathLib.Rounding rounding\n ) internal view returns (uint128 shares) {\n if (shareAmount == 0 || priceAssetPerShare_.raw() == 0) {\n return 0;\n }\n\n uint8 assetDecimals = getAssetDecimals(asset, tokenId);\n uint8 shareDecimals = IERC20Metadata(shareToken).decimals();\n\n return PricingLib.convertWithPrice(shareAmount, shareDecimals, assetDecimals, priceAssetPerShare_, rounding)\n .toUint128();\n }\n\n /// @dev Converts the given share amount to asset amount. Returned value is in share decimals.\n function shareToAssetAmount(\n address shareToken,\n uint128 shareAmount,\n address asset,\n uint256 tokenId,\n D18 pricePoolPerAsset,\n D18 pricePoolPerShare,\n MathLib.Rounding rounding\n ) internal view returns (uint128 shares) {\n if (shareAmount == 0 || pricePoolPerShare.raw() == 0 || pricePoolPerAsset.raw() == 0) {\n return 0;\n }\n\n uint8 assetDecimals = getAssetDecimals(asset, tokenId);\n uint8 shareDecimals = IERC20Metadata(shareToken).decimals();\n\n return PricingLib.shareToAssetAmount(\n shareAmount, shareDecimals, assetDecimals, pricePoolPerAsset, pricePoolPerShare, rounding\n ).toUint128();\n }\n\n /// @dev Calculates the asset price per share returns the value in price decimals\n /// Denominated in ASSET_UNIT/SHARE_UNIT\n function calculatePriceAssetPerShare(\n address shareToken,\n uint128 shares,\n address asset,\n uint256 tokenId,\n uint128 assets,\n MathLib.Rounding rounding\n ) internal view returns (uint256 priceAssetPerShare_) {\n if (assets == 0 || shares == 0) {\n return 0;\n }\n\n uint8 assetDecimals = getAssetDecimals(asset, tokenId);\n uint8 shareDecimals = IERC20Metadata(shareToken).decimals();\n\n // NOTE: More precise than d18(assets * 10 ** assetDecimals, shares * 10 ** shareDecimals)\n return toPriceDecimals(assets, assetDecimals).mulDiv(\n 10 ** PRICE_DECIMALS, toPriceDecimals(shares, shareDecimals), rounding\n );\n }\n\n /// -----------------------------------------------------\n /// Pure Methods\n /// -----------------------------------------------------\n\n /// @dev Converts an amount using decimals and price with implicit rounding down\n function convertWithPrice(uint256 baseAmount, uint8 baseDecimals, uint8 quoteDecimals, D18 priceQuotePerBase)\n internal\n pure\n returns (uint256 quoteAmount)\n {\n return convertWithPrice(baseAmount, baseDecimals, quoteDecimals, priceQuotePerBase, MathLib.Rounding.Down);\n }\n\n /// @dev Converts an amount using decimals and price with explicit rounding.\n function convertWithPrice(\n uint256 baseAmount,\n uint8 baseDecimals,\n uint8 quoteDecimals,\n D18 priceQuotePerBase,\n MathLib.Rounding rounding\n ) internal pure returns (uint256 quoteAmount) {\n if (baseDecimals == quoteDecimals) {\n return priceQuotePerBase.mulUint256(baseAmount, rounding);\n }\n\n return\n priceQuotePerBase.mulUint256(MathLib.mulDiv(baseAmount, 10 ** quoteDecimals, 10 ** baseDecimals), rounding);\n }\n\n /// @dev Converts an amount using decimals and reciprocal price.\n ///\n /// NOTE: More precise than convertWithPrice(,,,price.reciprocal,)\n function convertWithReciprocalPrice(\n uint256 baseAmount,\n uint8 baseDecimals,\n uint8 quoteDecimals,\n D18 priceBasePerQuote,\n MathLib.Rounding rounding\n ) internal pure returns (uint256 quoteAmount) {\n if (baseDecimals == quoteDecimals) {\n return priceBasePerQuote.reciprocalMulUint256(baseAmount, rounding);\n }\n\n return priceBasePerQuote.reciprocalMulUint256(\n MathLib.mulDiv(baseAmount, 10 ** quoteDecimals, 10 ** baseDecimals), rounding\n );\n }\n\n /// @dev Converts asset amount to share amount.\n function assetToShareAmount(\n uint256 assetAmount,\n uint8 assetDecimals,\n uint8 shareDecimals,\n D18 pricePoolPerAsset,\n D18 pricePoolPerShare,\n MathLib.Rounding rounding\n ) internal pure returns (uint256 shareAmount) {\n return pricePoolPerShare.reciprocalMulUint256(\n convertWithPrice(assetAmount, assetDecimals, shareDecimals, pricePoolPerAsset, MathLib.Rounding.Down),\n rounding\n );\n }\n\n /// @dev Converts share amount to asset asset amount.\n function shareToAssetAmount(\n uint256 shareAmount,\n uint8 shareDecimals,\n uint8 assetDecimals,\n D18 pricePoolPerAsset,\n D18 pricePoolPerShare,\n MathLib.Rounding rounding\n ) internal pure returns (uint256 assetAmount) {\n return convertWithReciprocalPrice(\n pricePoolPerShare.mulUint256(shareAmount, MathLib.Rounding.Down),\n shareDecimals,\n assetDecimals,\n pricePoolPerAsset,\n rounding\n );\n }\n\n /// @dev Converts pool amount to asset amount.\n function poolToAssetAmount(\n uint256 poolAmount,\n uint8 poolDecimals,\n uint8 assetDecimals,\n D18 pricePoolPerAsset,\n MathLib.Rounding rounding\n ) internal pure returns (uint256 assetAmount) {\n return convertWithReciprocalPrice(poolAmount, poolDecimals, assetDecimals, pricePoolPerAsset, rounding);\n }\n\n /// @dev Returns the asset price per share denominated in ASSET_UNIT/SHARE_UNIT\n ///\n /// @dev NOTE: Should never be used for calculating amounts due to precision loss. Instead, please refer to\n /// conversion relying on pricePoolPerShare and pricePoolPerAsset.\n function priceAssetPerShare(D18 pricePoolPerShare, D18 pricePoolPerAsset)\n internal\n pure\n returns (D18 priceAssetPerShare_)\n {\n return pricePoolPerShare / pricePoolPerAsset;\n }\n\n /// -----------------------------------------------------\n /// Private Methods\n /// -----------------------------------------------------\n\n /// @dev Returns the asset decimals\n function getAssetDecimals(address asset, uint256 tokenId) private view returns (uint8 assetDecimals) {\n return tokenId == 0 ? IERC20Metadata(asset).decimals() : IERC6909MetadataExt(asset).decimals(tokenId);\n }\n\n /// @dev When converting assets to shares using the price, all values are normalized to PRICE_DECIMALS\n /// @dev NOTE: We require all assets to have 2 <= decimals <= 18, see `PoolManager.registerAsset`\n function toPriceDecimals(uint128 _value, uint8 decimals) private pure returns (uint256) {\n if (PRICE_DECIMALS == decimals) return uint256(_value);\n return uint256(_value) * 10 ** (PRICE_DECIMALS - decimals);\n }\n\n /// @dev Converts decimals of the value from the price decimals back to the intended decimals\n /// @dev NOTE: We require all assets to have 2 <= decimals <= 18, see `PoolManager.registerAsset`\n function fromPriceDecimals(uint256 _value, uint8 decimals) private pure returns (uint128) {\n if (PRICE_DECIMALS == decimals) return _value.toUint128();\n return (_value / 10 ** (PRICE_DECIMALS - decimals)).toUint128();\n }\n}\n" + }, + "src/common/types/AccountId.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\ntype AccountId is uint32;\n\nfunction raw(AccountId accountId_) pure returns (uint32) {\n return AccountId.unwrap(accountId_);\n}\n\nusing {raw} for AccountId global;\n" + }, + "src/common/types/AssetId.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\n/// @dev Composite Id of the centrifugeId (uint16) where the asset resides\n/// and a local counter (uint64) that is part of the contract that registers the asset.\ntype AssetId is uint128;\n\nfunction isNull(AssetId assetId) pure returns (bool) {\n return AssetId.unwrap(assetId) == 0;\n}\n\nfunction addr(AssetId assetId) pure returns (address) {\n return address(uint160(AssetId.unwrap(assetId)));\n}\n\nfunction raw(AssetId assetId) pure returns (uint128) {\n return AssetId.unwrap(assetId);\n}\n\nfunction centrifugeId(AssetId assetId) pure returns (uint16) {\n return uint16(AssetId.unwrap(assetId) >> 112);\n}\n\nfunction newAssetId(uint16 centrifugeId_, uint64 counter) pure returns (AssetId) {\n return AssetId.wrap((uint128(centrifugeId_) << 112) + counter);\n}\n\nfunction newAssetId(uint32 isoCode) pure returns (AssetId) {\n return AssetId.wrap(isoCode);\n}\n\nfunction eq(AssetId a, AssetId b) pure returns (bool) {\n return a.raw() == b.raw();\n}\n\nusing {isNull, addr, raw, centrifugeId, eq} for AssetId global;\n" + }, + "src/common/types/PoolId.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\n\nusing MathLib for uint256;\n\ntype PoolId is uint64;\n\nfunction centrifugeId(PoolId poolId) pure returns (uint16) {\n return uint16(PoolId.unwrap(poolId) >> 48);\n}\n\nfunction newPoolId(uint16 centrifugeId_, uint48 localPoolId) pure returns (PoolId) {\n return PoolId.wrap((uint64(centrifugeId_) << 48) | uint64(localPoolId));\n}\n\nfunction isNull(PoolId poolId) pure returns (bool) {\n return PoolId.unwrap(poolId) == 0;\n}\n\nfunction raw(PoolId poolId) pure returns (uint64) {\n return PoolId.unwrap(poolId);\n}\n\nusing {centrifugeId, isNull, raw} for PoolId global;\n" + }, + "src/common/types/ShareClassId.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\n\ntype ShareClassId is bytes16;\n\nfunction isNull(ShareClassId scId) pure returns (bool) {\n return ShareClassId.unwrap(scId) == 0;\n}\n\nfunction equals(ShareClassId left, ShareClassId right) pure returns (bool) {\n return ShareClassId.unwrap(left) == ShareClassId.unwrap(right);\n}\n\nfunction raw(ShareClassId scId) pure returns (bytes16) {\n return ShareClassId.unwrap(scId);\n}\n\nfunction newShareClassId(PoolId poolId, uint32 index) pure returns (ShareClassId scId) {\n return ShareClassId.wrap(bytes16((uint128(PoolId.unwrap(poolId)) << 64) + index));\n}\n\nusing {isNull, raw, equals as ==} for ShareClassId global;\n" + }, + "src/hooks/FreezeOnly.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\nimport {BitmapLib} from \"src/misc/libraries/BitmapLib.sol\";\nimport {IERC165} from \"src/misc/interfaces/IERC7575.sol\";\n\nimport {IRoot} from \"src/common/interfaces/IRoot.sol\";\nimport {UpdateRestrictionType, MessageLib} from \"src/common/libraries/MessageLib.sol\";\n\nimport {IHook, HookData} from \"src/common/interfaces/IHook.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\n\nimport {IFreezable} from \"src/hooks/interfaces/IFreezable.sol\";\n\n/// @title Freeze Only\n/// @notice Hook implementation that:\n/// * Allows any non-frozen account to receive tokens and transfer tokens\n/// * Supports freezing accounts which blocks transfers both to and from them\n/// * Allows authTransferFrom calls\n///\n/// @dev The last bit of hookData is used to denote whether the account is frozen.\ncontract FreezeOnly is Auth, IFreezable, IHook {\n using BitmapLib for *;\n using MessageLib for *;\n using BytesLib for bytes;\n using CastLib for bytes32;\n\n /// @dev Least significant bit\n uint8 public constant FREEZE_BIT = 0;\n\n IRoot public immutable root;\n\n constructor(address root_, address deployer) Auth(deployer) {\n root = IRoot(root_);\n }\n\n //----------------------------------------------------------------------------------------------\n // Callback from share token\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHook\n function onERC20Transfer(address from, address to, uint256 value, HookData calldata hookData)\n external\n virtual\n returns (bytes4)\n {\n require(checkERC20Transfer(from, to, value, hookData), TransferBlocked());\n return IHook.onERC20Transfer.selector;\n }\n\n /// @inheritdoc IHook\n function onERC20AuthTransfer(\n address, /* sender */\n address, /* from */\n address, /* to */\n uint256, /* value */\n HookData calldata /* hookData */\n ) external pure returns (bytes4) {\n return IHook.onERC20AuthTransfer.selector;\n }\n\n /// @inheritdoc IHook\n function checkERC20Transfer(address from, address, /* to */ uint256, /* value */ HookData calldata hookData)\n public\n view\n returns (bool)\n {\n uint128 fromHookData = uint128(hookData.from);\n if (fromHookData.getBit(FREEZE_BIT) == true && !root.endorsed(from)) {\n // Source is frozen and not endorsed\n return false;\n }\n\n uint128 toHookData = uint128(hookData.to);\n if (toHookData.getBit(FREEZE_BIT) == true) {\n // Destination is frozen\n return false;\n }\n\n return true;\n }\n\n //----------------------------------------------------------------------------------------------\n // Restriction updates\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHook\n function updateRestriction(address token, bytes memory payload) external auth {\n UpdateRestrictionType updateId = payload.updateRestrictionType();\n\n if (updateId == UpdateRestrictionType.Freeze) {\n MessageLib.UpdateRestrictionFreeze memory m = payload.deserializeUpdateRestrictionFreeze();\n freeze(token, m.user.toAddress());\n } else if (updateId == UpdateRestrictionType.Unfreeze) {\n MessageLib.UpdateRestrictionUnfreeze memory m = payload.deserializeUpdateRestrictionUnfreeze();\n unfreeze(token, m.user.toAddress());\n } else {\n revert InvalidUpdate();\n }\n }\n\n /// @inheritdoc IFreezable\n function freeze(address token, address user) public auth {\n require(user != address(0), CannotFreezeZeroAddress());\n require(!root.endorsed(user), EndorsedUserCannotBeFrozen());\n\n uint128 hookData = uint128(IShareToken(token).hookDataOf(user));\n IShareToken(token).setHookData(user, bytes16(hookData.setBit(FREEZE_BIT, true)));\n\n emit Freeze(token, user);\n }\n\n /// @inheritdoc IFreezable\n function unfreeze(address token, address user) public auth {\n uint128 hookData = uint128(IShareToken(token).hookDataOf(user));\n IShareToken(token).setHookData(user, bytes16(hookData.setBit(FREEZE_BIT, false)));\n\n emit Unfreeze(token, user);\n }\n\n /// @inheritdoc IFreezable\n function isFrozen(address token, address user) public view returns (bool) {\n return uint128(IShareToken(token).hookDataOf(user)).getBit(FREEZE_BIT);\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-165\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC165\n function supportsInterface(bytes4 interfaceId) external pure override returns (bool) {\n return interfaceId == type(IHook).interfaceId || interfaceId == type(IERC165).interfaceId;\n }\n}\n" + }, + "src/hooks/FullRestrictions.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {BitmapLib} from \"src/misc/libraries/BitmapLib.sol\";\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\nimport {IERC165} from \"src/misc/interfaces/IERC7575.sol\";\n\nimport {UpdateRestrictionType, MessageLib} from \"src/common/libraries/MessageLib.sol\";\nimport {IRoot} from \"src/common/interfaces/IRoot.sol\";\n\nimport {IHook, HookData, ESCROW_HOOK_ID} from \"src/common/interfaces/IHook.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\n\nimport {IFreezable} from \"src/hooks/interfaces/IFreezable.sol\";\nimport {IMemberlist} from \"src/hooks/interfaces/IMemberlist.sol\";\n\n/// @title Full Restrictions\n/// @notice Hook implementation that:\n/// * Requires adding accounts to the memberlist before they can receive tokens\n/// * Supports freezing accounts which blocks transfers both to and from them\n/// * Allows authTransferFrom calls\n///\n/// @dev The first 8 bytes (uint64) of hookData is used for the memberlist valid until date,\n/// the last bit is used to denote whether the account is frozen.\ncontract FullRestrictions is Auth, IMemberlist, IFreezable, IHook {\n using BitmapLib for *;\n using MessageLib for *;\n using BytesLib for bytes;\n using CastLib for bytes32;\n\n /// @dev Least significant bit\n uint8 public constant FREEZE_BIT = 0;\n\n IRoot public immutable root;\n\n constructor(address root_, address deployer) Auth(deployer) {\n root = IRoot(root_);\n }\n\n //----------------------------------------------------------------------------------------------\n // Callback from share token\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHook\n function onERC20Transfer(address from, address to, uint256 value, HookData calldata hookData)\n external\n virtual\n returns (bytes4)\n {\n require(checkERC20Transfer(from, to, value, hookData), TransferBlocked());\n return IHook.onERC20Transfer.selector;\n }\n\n /// @inheritdoc IHook\n function onERC20AuthTransfer(\n address, /* sender */\n address, /* from */\n address, /* to */\n uint256, /* value */\n HookData calldata /* hookData */\n ) external pure returns (bytes4) {\n return IHook.onERC20AuthTransfer.selector;\n }\n\n /// @inheritdoc IHook\n function checkERC20Transfer(address from, address to, uint256, /* value */ HookData calldata hookData)\n public\n view\n returns (bool)\n {\n if (uint128(hookData.from).getBit(FREEZE_BIT) == true && !root.endorsed(from) && from != ESCROW_HOOK_ID) {\n // Source is frozen and not endorsed\n return false;\n }\n\n if (root.endorsed(to) || to == address(0) || to == ESCROW_HOOK_ID) {\n // Destination is endorsed or escrow and source was already checked, so the transfer is allowed\n return true;\n }\n\n uint128 toHookData = uint128(hookData.to);\n if (toHookData.getBit(FREEZE_BIT) == true) {\n // Destination is frozen\n return false;\n }\n\n if (toHookData >> 64 < block.timestamp) {\n // Destination is not a member\n return false;\n }\n\n return true;\n }\n\n //----------------------------------------------------------------------------------------------\n // Restriction updates\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHook\n function updateRestriction(address token, bytes memory payload) external auth {\n UpdateRestrictionType updateId = payload.updateRestrictionType();\n\n if (updateId == UpdateRestrictionType.Member) {\n MessageLib.UpdateRestrictionMember memory m = payload.deserializeUpdateRestrictionMember();\n updateMember(token, m.user.toAddress(), m.validUntil);\n } else if (updateId == UpdateRestrictionType.Freeze) {\n MessageLib.UpdateRestrictionFreeze memory m = payload.deserializeUpdateRestrictionFreeze();\n freeze(token, m.user.toAddress());\n } else if (updateId == UpdateRestrictionType.Unfreeze) {\n MessageLib.UpdateRestrictionUnfreeze memory m = payload.deserializeUpdateRestrictionUnfreeze();\n unfreeze(token, m.user.toAddress());\n } else {\n revert InvalidUpdate();\n }\n }\n\n /// @inheritdoc IFreezable\n function freeze(address token, address user) public auth {\n require(user != address(0), CannotFreezeZeroAddress());\n require(!root.endorsed(user), EndorsedUserCannotBeFrozen());\n\n uint128 hookData = uint128(IShareToken(token).hookDataOf(user));\n IShareToken(token).setHookData(user, bytes16(hookData.setBit(FREEZE_BIT, true)));\n\n emit Freeze(token, user);\n }\n\n /// @inheritdoc IFreezable\n function unfreeze(address token, address user) public auth {\n uint128 hookData = uint128(IShareToken(token).hookDataOf(user));\n IShareToken(token).setHookData(user, bytes16(hookData.setBit(FREEZE_BIT, false)));\n\n emit Unfreeze(token, user);\n }\n\n /// @inheritdoc IFreezable\n function isFrozen(address token, address user) public view returns (bool) {\n return uint128(IShareToken(token).hookDataOf(user)).getBit(FREEZE_BIT);\n }\n\n /// @inheritdoc IMemberlist\n function updateMember(address token, address user, uint64 validUntil) public auth {\n require(block.timestamp <= validUntil, InvalidValidUntil());\n require(!root.endorsed(user), EndorsedUserCannotBeUpdated());\n\n uint128 hookData = uint128(validUntil) << 64;\n hookData.setBit(FREEZE_BIT, isFrozen(token, user));\n IShareToken(token).setHookData(user, bytes16(hookData));\n\n emit UpdateMember(token, user, validUntil);\n }\n\n /// @inheritdoc IMemberlist\n function isMember(address token, address user) external view returns (bool isValid, uint64 validUntil) {\n validUntil = abi.encodePacked(IShareToken(token).hookDataOf(user)).toUint64(0);\n isValid = validUntil >= block.timestamp;\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-165\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC165\n function supportsInterface(bytes4 interfaceId) external pure override returns (bool) {\n return interfaceId == type(IHook).interfaceId || interfaceId == type(IERC165).interfaceId;\n }\n}\n" + }, + "src/hooks/RedemptionRestrictions.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\nimport {BitmapLib} from \"src/misc/libraries/BitmapLib.sol\";\nimport {IERC165} from \"src/misc/interfaces/IERC7575.sol\";\n\nimport {IRoot} from \"src/common/interfaces/IRoot.sol\";\nimport {UpdateRestrictionType, MessageLib} from \"src/common/libraries/MessageLib.sol\";\n\nimport {IHook, HookData, ESCROW_HOOK_ID} from \"src/common/interfaces/IHook.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\n\nimport {IFreezable} from \"src/hooks/interfaces/IFreezable.sol\";\nimport {IMemberlist} from \"src/hooks/interfaces/IMemberlist.sol\";\n\n/// @title Redemption Restrictions\n/// @notice Hook implementation that:\n/// * Allows any non-frozen account to receive tokens and transfer tokens\n/// * Requires accounts to be added as a member before submitting a redemption request\n/// * Supports freezing accounts which blocks transfers both to and from them\n/// * Allows authTransferFrom calls\n///\n/// @dev The first 8 bytes (uint64) of hookData is used for the memberlist valid until date,\n/// the last bit is used to denote whether the account is frozen.\ncontract RedemptionRestrictions is Auth, IMemberlist, IFreezable, IHook {\n using BitmapLib for *;\n using MessageLib for *;\n using BytesLib for bytes;\n using CastLib for bytes32;\n\n /// @dev Least significant bit\n uint8 public constant FREEZE_BIT = 0;\n\n IRoot public immutable root;\n\n constructor(address root_, address deployer) Auth(deployer) {\n root = IRoot(root_);\n }\n\n //----------------------------------------------------------------------------------------------\n // Callback from share token\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHook\n function onERC20Transfer(address from, address to, uint256 value, HookData calldata hookData)\n external\n virtual\n returns (bytes4)\n {\n require(checkERC20Transfer(from, to, value, hookData), TransferBlocked());\n return IHook.onERC20Transfer.selector;\n }\n\n /// @inheritdoc IHook\n function onERC20AuthTransfer(\n address, /* sender */\n address, /* from */\n address, /* to */\n uint256, /* value */\n HookData calldata /* hookData */\n ) external pure returns (bytes4) {\n return IHook.onERC20AuthTransfer.selector;\n }\n\n /// @inheritdoc IHook\n function checkERC20Transfer(address from, address to, uint256, /* value */ HookData calldata hookData)\n public\n view\n returns (bool)\n {\n uint128 fromHookData = uint128(hookData.from);\n if (fromHookData.getBit(FREEZE_BIT) == true && !root.endorsed(from)) {\n // Source is frozen and not endorsed\n return false;\n }\n\n uint128 toHookData = uint128(hookData.to);\n if (toHookData.getBit(FREEZE_BIT) == true) {\n // Destination is frozen\n return false;\n }\n\n if (from == address(0) && to == ESCROW_HOOK_ID) {\n // Deposit request fulfillment\n return true;\n }\n\n if (to == ESCROW_HOOK_ID && fromHookData >> 64 < block.timestamp) {\n // Destination is escrow, so it's a redemption request, and the user is not a member\n return false;\n }\n\n return true;\n }\n\n //----------------------------------------------------------------------------------------------\n // Restriction updates\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHook\n function updateRestriction(address token, bytes memory payload) external auth {\n UpdateRestrictionType updateId = payload.updateRestrictionType();\n\n if (updateId == UpdateRestrictionType.Member) {\n MessageLib.UpdateRestrictionMember memory m = payload.deserializeUpdateRestrictionMember();\n updateMember(token, m.user.toAddress(), m.validUntil);\n } else if (updateId == UpdateRestrictionType.Freeze) {\n MessageLib.UpdateRestrictionFreeze memory m = payload.deserializeUpdateRestrictionFreeze();\n freeze(token, m.user.toAddress());\n } else if (updateId == UpdateRestrictionType.Unfreeze) {\n MessageLib.UpdateRestrictionUnfreeze memory m = payload.deserializeUpdateRestrictionUnfreeze();\n unfreeze(token, m.user.toAddress());\n } else {\n revert InvalidUpdate();\n }\n }\n\n /// @inheritdoc IFreezable\n function freeze(address token, address user) public auth {\n require(user != address(0), CannotFreezeZeroAddress());\n require(!root.endorsed(user), EndorsedUserCannotBeFrozen());\n\n uint128 hookData = uint128(IShareToken(token).hookDataOf(user));\n IShareToken(token).setHookData(user, bytes16(hookData.setBit(FREEZE_BIT, true)));\n\n emit Freeze(token, user);\n }\n\n /// @inheritdoc IFreezable\n function unfreeze(address token, address user) public auth {\n uint128 hookData = uint128(IShareToken(token).hookDataOf(user));\n IShareToken(token).setHookData(user, bytes16(hookData.setBit(FREEZE_BIT, false)));\n\n emit Unfreeze(token, user);\n }\n\n /// @inheritdoc IFreezable\n function isFrozen(address token, address user) public view returns (bool) {\n return uint128(IShareToken(token).hookDataOf(user)).getBit(FREEZE_BIT);\n }\n\n /// @inheritdoc IMemberlist\n function updateMember(address token, address user, uint64 validUntil) public auth {\n require(block.timestamp <= validUntil, InvalidValidUntil());\n require(!root.endorsed(user), EndorsedUserCannotBeUpdated());\n\n uint128 hookData = uint128(validUntil) << 64;\n hookData.setBit(FREEZE_BIT, isFrozen(token, user));\n IShareToken(token).setHookData(user, bytes16(hookData));\n\n emit UpdateMember(token, user, validUntil);\n }\n\n /// @inheritdoc IMemberlist\n function isMember(address token, address user) external view returns (bool isValid, uint64 validUntil) {\n validUntil = abi.encodePacked(IShareToken(token).hookDataOf(user)).toUint64(0);\n isValid = validUntil >= block.timestamp;\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-165\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC165\n function supportsInterface(bytes4 interfaceId) external pure override returns (bool) {\n return interfaceId == type(IHook).interfaceId || interfaceId == type(IERC165).interfaceId;\n }\n}\n" + }, + "src/hooks/interfaces/IFreezable.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\ninterface IFreezable {\n // --- Events ---\n event Freeze(address indexed token, address indexed user);\n event Unfreeze(address indexed token, address indexed user);\n\n // --- Errors ---\n error CannotFreezeZeroAddress();\n error EndorsedUserCannotBeFrozen();\n\n // --- Handling freezes ---\n /// @notice Freeze a user balance. Frozen users cannot receive nor send tokens\n function freeze(address token, address user) external;\n\n /// @notice Unfreeze a user balance\n function unfreeze(address token, address user) external;\n\n /// @notice Returns whether the user's tokens are frozen\n function isFrozen(address token, address user) external view returns (bool);\n}\n" + }, + "src/hooks/interfaces/IMemberlist.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\ninterface IMemberlist {\n // --- Events ---\n event UpdateMember(address indexed token, address indexed user, uint64 validUntil);\n\n // --- Errors ---\n error InvalidValidUntil();\n error EndorsedUserCannotBeUpdated();\n\n // --- Managing members ---\n /// @notice Add a member. Non-members cannot receive tokens, but can send tokens to valid members\n /// @param validUntil Timestamp until which the user will be a valid member\n function updateMember(address token, address user, uint64 validUntil) external;\n\n /// @notice Returns whether the user is a valid member of the token\n function isMember(address token, address user) external view returns (bool isValid, uint64 validUntil);\n}\n" + }, + "src/hub/Accounting.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\n\nimport {AccountId} from \"src/common/types/AccountId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {IAccounting, JournalEntry} from \"src/hub/interfaces/IAccounting.sol\";\nimport {TransientStorageLib} from \"src/misc/libraries/TransientStorageLib.sol\";\n\n/// @notice In a transaction there can be multiple journal entries for different pools,\n/// which can be interleaved. We want entries for the same pool to share the same journal ID.\n/// So we're keeping a journal ID per pool in transient storage.\nlibrary TransientJournal {\n function journalId(PoolId poolId) internal view returns (uint256) {\n return TransientStorageLib.tloadUint256(keccak256(abi.encode(\"journalId\", poolId)));\n }\n\n function setJournalId(PoolId poolId, uint256 value) internal {\n TransientStorageLib.tstore(keccak256(abi.encode(\"journalId\", poolId)), value);\n }\n}\n\n/// @title Accounting\n/// @notice Double-entry bookkeeping system.\n/// @dev To add entries, a specific pool needs to be unlocked.\n/// When locking, the debited and credited amounts need to match.\ncontract Accounting is Auth, IAccounting {\n mapping(PoolId => mapping(AccountId => Account)) public accounts;\n\n uint128 public transient debited;\n uint128 public transient credited;\n PoolId internal transient _currentPoolId;\n mapping(PoolId => uint64) internal _poolJournalIdCounter;\n\n constructor(address deployer) Auth(deployer) {}\n\n //----------------------------------------------------------------------------------------------\n // Lock/unlock\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IAccounting\n function unlock(PoolId poolId) external auth {\n require(PoolId.unwrap(_currentPoolId) == 0, AccountingAlreadyUnlocked());\n debited = 0;\n credited = 0;\n _currentPoolId = poolId;\n\n if (TransientJournal.journalId(poolId) == 0) {\n TransientJournal.setJournalId(poolId, _generateJournalId(poolId));\n }\n emit StartJournalId(poolId, TransientJournal.journalId(poolId));\n }\n\n /// @inheritdoc IAccounting\n function lock() external auth {\n require(debited == credited, Unbalanced());\n\n emit EndJournalId(_currentPoolId, TransientJournal.journalId(_currentPoolId));\n _currentPoolId = PoolId.wrap(0);\n }\n\n //----------------------------------------------------------------------------------------------\n // Account creation & metadata\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IAccounting\n function createAccount(PoolId poolId, AccountId account, bool isDebitNormal) external auth {\n require(accounts[poolId][account].lastUpdated == 0, AccountExists());\n accounts[poolId][account] = Account(0, 0, isDebitNormal, uint64(block.timestamp), \"\");\n emit CreateAccount(poolId, account, isDebitNormal);\n }\n\n /// @inheritdoc IAccounting\n function setAccountMetadata(PoolId poolId, AccountId account, bytes calldata metadata) external auth {\n require(accounts[poolId][account].lastUpdated != 0, AccountDoesNotExist());\n accounts[poolId][account].metadata = metadata;\n emit SetAccountMetadata(poolId, account, metadata);\n }\n \n //----------------------------------------------------------------------------------------------\n // Account updates\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IAccounting\n function addDebit(AccountId account, uint128 value) public auth {\n require(!_currentPoolId.isNull(), AccountingLocked());\n\n Account storage acc = accounts[_currentPoolId][account];\n require(acc.lastUpdated != 0, AccountDoesNotExist());\n\n acc.totalDebit += value;\n debited += value;\n acc.lastUpdated = uint64(block.timestamp);\n emit Debit(_currentPoolId, account, value);\n }\n\n /// @inheritdoc IAccounting\n function addCredit(AccountId account, uint128 value) public auth {\n require(!_currentPoolId.isNull(), AccountingLocked());\n\n Account storage acc = accounts[_currentPoolId][account];\n require(acc.lastUpdated != 0, AccountDoesNotExist());\n\n acc.totalCredit += value;\n credited += value;\n acc.lastUpdated = uint64(block.timestamp);\n emit Credit(_currentPoolId, account, value);\n }\n\n /// @inheritdoc IAccounting\n function addJournal(JournalEntry[] memory debits, JournalEntry[] memory credits) external auth {\n for (uint256 i; i < debits.length; i++) {\n addDebit(debits[i].accountId, debits[i].value);\n }\n\n for (uint256 i; i < credits.length; i++) {\n addCredit(credits[i].accountId, credits[i].value);\n }\n }\n\n //----------------------------------------------------------------------------------------------\n // View methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IAccounting\n function accountValue(PoolId poolId, AccountId account) external view returns (bool /* isPositive */, uint128) {\n Account storage acc = accounts[poolId][account];\n require(acc.lastUpdated != 0, AccountDoesNotExist());\n\n if (acc.isDebitNormal) {\n // For debit-normal accounts: Value = Total Debit - Total Credit\n if (acc.totalDebit >= acc.totalCredit) {\n return (true, acc.totalDebit - acc.totalCredit);\n } else {\n return (false, acc.totalCredit - acc.totalDebit);\n }\n } else {\n // For credit-normal accounts: Value = Total Credit - Total Debit\n if (acc.totalCredit >= acc.totalDebit) {\n return (true, acc.totalCredit - acc.totalDebit);\n } else {\n return (false, acc.totalDebit - acc.totalCredit);\n }\n }\n }\n\n /// @inheritdoc IAccounting\n function exists(PoolId poolId, AccountId account) external view returns (bool) {\n return accounts[poolId][account].lastUpdated != 0;\n }\n\n function _generateJournalId(PoolId poolId) internal returns (uint256) {\n return uint256((uint256(poolId.raw()) << 128) | ++_poolJournalIdCounter[poolId]);\n }\n}\n" + }, + "src/hub/Holdings.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IERC7726} from \"src/misc/interfaces/IERC7726.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {d18, D18} from \"src/misc/types/D18.sol\";\n\nimport {PricingLib} from \"src/common/libraries/PricingLib.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {AccountId} from \"src/common/types/AccountId.sol\";\nimport {IHoldings, Holding} from \"src/hub/interfaces/IHoldings.sol\";\nimport {IHubRegistry} from \"src/hub/interfaces/IHubRegistry.sol\";\nimport {IHoldings, Holding, HoldingAccount} from \"src/hub/interfaces/IHoldings.sol\";\n\n/// @title Holdings\n/// @notice Bookkeeping of the holdings and its associated accounting IDs for each pool.\ncontract Holdings is Auth, IHoldings {\n using MathLib for uint256;\n\n IHubRegistry public immutable hubRegistry;\n\n mapping(PoolId => mapping(ShareClassId => mapping(AssetId => Holding))) public holding;\n mapping(PoolId => mapping(ShareClassId => mapping(AssetId => mapping(uint8 kind => AccountId)))) public accountId;\n\n constructor(IHubRegistry hubRegistry_, address deployer) Auth(deployer) {\n hubRegistry = hubRegistry_;\n }\n\n //----------------------------------------------------------------------------------------------\n // Holding creation & updates\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHoldings\n function create(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n IERC7726 valuation_,\n bool isLiability_,\n HoldingAccount[] memory accounts\n ) external auth {\n require(!scId.isNull(), WrongShareClassId());\n require(address(valuation_) != address(0), WrongValuation());\n\n holding[poolId][scId][assetId] = Holding(0, 0, valuation_, isLiability_);\n\n for (uint256 i; i < accounts.length; i++) {\n accountId[poolId][scId][assetId][accounts[i].kind] = accounts[i].accountId;\n }\n\n emit Create(poolId, scId, assetId, valuation_, isLiability_, accounts);\n }\n\n /// @inheritdoc IHoldings\n function setAccountId(PoolId poolId, ShareClassId scId, AssetId assetId, uint8 kind, AccountId accountId_)\n external\n auth\n {\n Holding storage holding_ = holding[poolId][scId][assetId];\n require(address(holding_.valuation) != address(0), HoldingNotFound());\n\n accountId[poolId][scId][assetId][kind] = accountId_;\n\n emit SetAccountId(poolId, scId, assetId, kind, accountId_);\n }\n\n /// @inheritdoc IHoldings\n function updateValuation(PoolId poolId, ShareClassId scId, AssetId assetId, IERC7726 valuation_) external auth {\n require(address(valuation_) != address(0), WrongValuation());\n\n Holding storage holding_ = holding[poolId][scId][assetId];\n require(address(holding_.valuation) != address(0), HoldingNotFound());\n\n holding_.valuation = valuation_;\n\n emit UpdateValuation(poolId, scId, assetId, valuation_);\n }\n\n //----------------------------------------------------------------------------------------------\n // Value updates\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHoldings\n function increase(PoolId poolId, ShareClassId scId, AssetId assetId, D18 pricePoolPerAsset, uint128 amount_)\n external\n auth\n returns (uint128 amountValue)\n {\n Holding storage holding_ = holding[poolId][scId][assetId];\n require(address(holding_.valuation) != address(0), HoldingNotFound());\n\n amountValue = PricingLib.convertWithPrice(\n amount_, hubRegistry.decimals(assetId), hubRegistry.decimals(poolId), pricePoolPerAsset\n ).toUint128();\n\n holding_.assetAmount += amount_;\n holding_.assetAmountValue += amountValue;\n\n emit Increase(poolId, scId, assetId, pricePoolPerAsset, amount_, amountValue);\n }\n\n /// @inheritdoc IHoldings\n function decrease(PoolId poolId, ShareClassId scId, AssetId assetId, D18 pricePoolPerAsset, uint128 amount_)\n external\n auth\n returns (uint128 amountValue)\n {\n Holding storage holding_ = holding[poolId][scId][assetId];\n require(address(holding_.valuation) != address(0), HoldingNotFound());\n\n amountValue = PricingLib.convertWithPrice(\n amount_, hubRegistry.decimals(assetId), hubRegistry.decimals(poolId), pricePoolPerAsset\n ).toUint128();\n\n holding_.assetAmount -= amount_;\n holding_.assetAmountValue -= amountValue;\n\n emit Decrease(poolId, scId, assetId, pricePoolPerAsset, amount_, amountValue);\n }\n\n /// @inheritdoc IHoldings\n function update(PoolId poolId, ShareClassId scId, AssetId assetId)\n external\n auth\n returns (bool isPositive, uint128 diffValue)\n {\n Holding storage holding_ = holding[poolId][scId][assetId];\n require(address(holding_.valuation) != address(0), HoldingNotFound());\n\n uint128 currentAmountValue = holding_.valuation.getQuote(\n holding_.assetAmount, assetId.addr(), hubRegistry.currency(poolId).addr()\n ).toUint128();\n\n isPositive = currentAmountValue >= holding_.assetAmountValue;\n diffValue =\n isPositive ? currentAmountValue - holding_.assetAmountValue : holding_.assetAmountValue - currentAmountValue;\n\n holding_.assetAmountValue = currentAmountValue;\n\n emit Update(poolId, scId, assetId, isPositive, diffValue);\n }\n\n //----------------------------------------------------------------------------------------------\n // View methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHoldings\n function value(PoolId poolId, ShareClassId scId, AssetId assetId) external view returns (uint128 value_) {\n Holding storage holding_ = holding[poolId][scId][assetId];\n require(address(holding_.valuation) != address(0), HoldingNotFound());\n\n return holding_.assetAmountValue;\n }\n\n /// @inheritdoc IHoldings\n function amount(PoolId poolId, ShareClassId scId, AssetId assetId) external view returns (uint128 amount_) {\n Holding storage holding_ = holding[poolId][scId][assetId];\n require(address(holding_.valuation) != address(0), HoldingNotFound());\n\n return holding_.assetAmount;\n }\n\n /// @inheritdoc IHoldings\n function valuation(PoolId poolId, ShareClassId scId, AssetId assetId) external view returns (IERC7726) {\n Holding storage holding_ = holding[poolId][scId][assetId];\n require(address(holding_.valuation) != address(0), HoldingNotFound());\n\n return holding_.valuation;\n }\n\n /// @inheritdoc IHoldings\n function isLiability(PoolId poolId, ShareClassId scId, AssetId assetId) external view returns (bool) {\n Holding storage holding_ = holding[poolId][scId][assetId];\n require(address(holding_.valuation) != address(0), HoldingNotFound());\n\n return holding_.isLiability;\n }\n\n /// @inheritdoc IHoldings\n function exists(PoolId poolId, ShareClassId scId, AssetId assetId) external view returns (bool) {\n return address(holding[poolId][scId][assetId].valuation) != address(0);\n }\n}\n" + }, + "src/hub/Hub.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {D18, d18} from \"src/misc/types/D18.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {IERC7726} from \"src/misc/interfaces/IERC7726.sol\";\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {Multicall, IMulticall} from \"src/misc/Multicall.sol\";\nimport {Recoverable} from \"src/misc/Recoverable.sol\";\n\nimport {IGateway} from \"src/common/interfaces/IGateway.sol\";\nimport {IHubGatewayHandler} from \"src/common/interfaces/IGatewayHandlers.sol\";\nimport {IPoolMessageSender} from \"src/common/interfaces/IGatewaySenders.sol\";\nimport {IHubGuardianActions} from \"src/common/interfaces/IGuardianActions.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {AccountId} from \"src/common/types/AccountId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\n\nimport {IAccounting, JournalEntry} from \"src/hub/interfaces/IAccounting.sol\";\nimport {IHubRegistry} from \"src/hub/interfaces/IHubRegistry.sol\";\nimport {IShareClassManager} from \"src/hub/interfaces/IShareClassManager.sol\";\nimport {IHoldings, HoldingAccount} from \"src/hub/interfaces/IHoldings.sol\";\nimport {IHub, AccountType} from \"src/hub/interfaces/IHub.sol\";\n\n/// @title Hub\n/// @notice Central pool management contract, that brings together all functions in one place.\n/// Pools can assign hub managers which have full rights over all actions.\n///\n/// Also acts as the central contract that routes messages from other chains to the Hub contracts.\ncontract Hub is Multicall, Auth, Recoverable, IHub, IHubGatewayHandler, IHubGuardianActions {\n using MathLib for uint256;\n\n IHubRegistry public immutable hubRegistry;\n\n IGateway public gateway;\n IHoldings public holdings;\n IAccounting public accounting;\n IPoolMessageSender public sender;\n IShareClassManager public shareClassManager;\n\n constructor(\n IShareClassManager shareClassManager_,\n IHubRegistry hubRegistry_,\n IAccounting accounting_,\n IHoldings holdings_,\n IGateway gateway_,\n address deployer\n ) Auth(deployer) {\n shareClassManager = shareClassManager_;\n hubRegistry = hubRegistry_;\n accounting = accounting_;\n holdings = holdings_;\n gateway = gateway_;\n }\n\n //----------------------------------------------------------------------------------------------\n // System methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHub\n function file(bytes32 what, address data) external {\n _auth();\n\n if (what == \"sender\") sender = IPoolMessageSender(data);\n else if (what == \"holdings\") holdings = IHoldings(data);\n else if (what == \"accounting\") accounting = IAccounting(data);\n else if (what == \"shareClassManager\") shareClassManager = IShareClassManager(data);\n else if (what == \"gateway\") gateway = IGateway(data);\n else revert FileUnrecognizedParam();\n\n emit File(what, data);\n }\n\n /// @inheritdoc IMulticall\n /// @notice performs a multicall but all messages sent in the process will be batched\n function multicall(bytes[] calldata data) public payable override {\n bool wasBatching = gateway.isBatching();\n if (!wasBatching) {\n gateway.startBatching();\n gateway.payTransaction{value: msg.value}(msg.sender);\n }\n\n super.multicall(data);\n\n if (!wasBatching) {\n gateway.endBatching();\n }\n }\n\n /// @inheritdoc IHubGuardianActions\n function createPool(PoolId poolId, address admin, AssetId currency) external payable {\n _auth();\n\n require(poolId.centrifugeId() == sender.localCentrifugeId(), InvalidPoolId());\n hubRegistry.registerPool(poolId, admin, currency);\n }\n\n //----------------------------------------------------------------------------------------------\n // Permissionless methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHub\n function notifyDeposit(PoolId poolId, ShareClassId scId, AssetId assetId, bytes32 investor, uint32 maxClaims)\n external\n payable\n {\n _pay();\n\n uint128 totalPayoutShareAmount;\n uint128 totalPaymentAssetAmount;\n uint128 cancelledAssetAmount;\n\n for (uint32 i = 0; i < maxClaims; i++) {\n (uint128 payoutShareAmount, uint128 paymentAssetAmount, uint128 cancelled, bool canClaimAgain) =\n shareClassManager.claimDeposit(poolId, scId, investor, assetId);\n\n totalPayoutShareAmount += payoutShareAmount;\n totalPaymentAssetAmount += paymentAssetAmount;\n\n // Should be written at most once with non-zero amount iff the last claimable epoch was processed and\n // the user had a pending cancellation\n // NOTE: Purposely delaying corresponding message dispatch after deposit fulfillment message\n if (cancelled > 0) {\n cancelledAssetAmount = cancelled;\n }\n\n if (!canClaimAgain) {\n break;\n }\n }\n\n sender.sendFulfilledDepositRequest(\n poolId, scId, assetId, investor, totalPaymentAssetAmount, totalPayoutShareAmount\n );\n\n // If cancellation was queued, notify about delayed cancellation\n if (cancelledAssetAmount > 0) {\n sender.sendFulfilledCancelDepositRequest(poolId, scId, assetId, investor, cancelledAssetAmount);\n }\n }\n\n /// @inheritdoc IHub\n function notifyRedeem(PoolId poolId, ShareClassId scId, AssetId assetId, bytes32 investor, uint32 maxClaims)\n external\n payable\n {\n _pay();\n\n uint128 totalPayoutAssetAmount;\n uint128 totalPaymentShareAmount;\n uint128 cancelledShareAmount;\n\n for (uint32 i = 0; i < maxClaims; i++) {\n (uint128 payoutAssetAmount, uint128 paymentShareAmount, uint128 cancelled, bool canClaimAgain) =\n shareClassManager.claimRedeem(poolId, scId, investor, assetId);\n\n totalPayoutAssetAmount += payoutAssetAmount;\n totalPaymentShareAmount += paymentShareAmount;\n\n // Should be written at most once with non-zero amount iff the last claimable epoch was processed and\n // the user had a pending cancellation\n // NOTE: Purposely delaying corresponding message dispatch after redemption fulfillment message\n if (cancelled > 0) {\n cancelledShareAmount = cancelled;\n }\n\n if (!canClaimAgain) {\n break;\n }\n }\n\n sender.sendFulfilledRedeemRequest(\n poolId, scId, assetId, investor, totalPayoutAssetAmount, totalPaymentShareAmount\n );\n\n // If cancellation was queued, notify about delayed cancellation\n if (cancelledShareAmount > 0) {\n sender.sendFulfilledCancelRedeemRequest(poolId, scId, assetId, investor, cancelledShareAmount);\n }\n }\n\n //----------------------------------------------------------------------------------------------\n // Pool admin methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHub\n function notifyPool(PoolId poolId, uint16 centrifugeId) external payable {\n _isManagerAndPaid(poolId);\n\n emit NotifyPool(centrifugeId, poolId);\n sender.sendNotifyPool(centrifugeId, poolId);\n }\n\n /// @inheritdoc IHub\n function notifyShareClass(PoolId poolId, ShareClassId scId, uint16 centrifugeId, bytes32 hook) external payable {\n _isManagerAndPaid(poolId);\n\n require(shareClassManager.exists(poolId, scId), IShareClassManager.ShareClassNotFound());\n\n (string memory name, string memory symbol, bytes32 salt) = shareClassManager.metadata(scId);\n uint8 decimals = hubRegistry.decimals(poolId);\n\n emit NotifyShareClass(centrifugeId, poolId, scId);\n sender.sendNotifyShareClass(centrifugeId, poolId, scId, name, symbol, decimals, salt, hook);\n }\n\n /// @inheritdoc IHub\n function notifyShareMetadata(PoolId poolId, ShareClassId scId, uint16 centrifugeId) public payable {\n _isManagerAndPaid(poolId);\n\n (string memory name, string memory symbol,) = shareClassManager.metadata(scId);\n\n emit NotifyShareMetadata(centrifugeId, poolId, scId, name, symbol);\n sender.sendNotifyShareMetadata(centrifugeId, poolId, scId, name, symbol);\n }\n\n /// @inheritdoc IHub\n function updateShareHook(PoolId poolId, ShareClassId scId, uint16 centrifugeId, bytes32 hook) public payable {\n _isManagerAndPaid(poolId);\n\n emit UpdateShareHook(centrifugeId, poolId, scId, hook);\n sender.sendUpdateShareHook(centrifugeId, poolId, scId, hook);\n }\n\n /// @inheritdoc IHub\n function notifySharePrice(PoolId poolId, ShareClassId scId, uint16 centrifugeId) public payable {\n _isManagerAndPaid(poolId);\n\n (, D18 poolPerShare) = shareClassManager.metrics(scId);\n\n emit NotifySharePrice(centrifugeId, poolId, scId, poolPerShare);\n sender.sendNotifyPricePoolPerShare(centrifugeId, poolId, scId, poolPerShare);\n }\n\n /// @inheritdoc IHub\n function notifyAssetPrice(PoolId poolId, ShareClassId scId, AssetId assetId) public payable {\n _isManagerAndPaid(poolId);\n D18 pricePoolPerAsset = _pricePoolPerAsset(poolId, scId, assetId);\n emit NotifyAssetPrice(assetId.centrifugeId(), poolId, scId, assetId, pricePoolPerAsset);\n sender.sendNotifyPricePoolPerAsset(poolId, scId, assetId, pricePoolPerAsset);\n }\n\n /// @inheritdoc IHub\n function triggerIssueShares(uint16 centrifugeId, PoolId poolId, ShareClassId scId, address who, uint128 shares)\n public\n payable\n {\n _isManagerAndPaid(poolId);\n\n sender.sendTriggerIssueShares(centrifugeId, poolId, scId, who, shares);\n }\n\n /// @inheritdoc IHub\n function triggerSubmitQueuedShares(uint16 centrifugeId, PoolId poolId, ShareClassId scId) public payable {\n _isManagerAndPaid(poolId);\n\n sender.sendTriggerSubmitQueuedShares(centrifugeId, poolId, scId);\n }\n\n /// @inheritdoc IHub\n function triggerSubmitQueuedAssets(PoolId poolId, ShareClassId scId, AssetId assetId) public payable {\n _isManagerAndPaid(poolId);\n\n sender.sendTriggerSubmitQueuedAssets(poolId, scId, assetId);\n }\n\n /// @inheritdoc IHub\n function setQueue(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bool enabled) public payable {\n _isManagerAndPaid(poolId);\n\n sender.sendSetQueue(centrifugeId, poolId, scId, enabled);\n }\n\n /// @inheritdoc IHub\n function setPoolMetadata(PoolId poolId, bytes calldata metadata) external payable {\n _isManager(poolId);\n\n hubRegistry.setMetadata(poolId, metadata);\n }\n\n /// @inheritdoc IHub\n function updateShareClassMetadata(PoolId poolId, ShareClassId scId, string calldata name, string calldata symbol)\n external\n payable\n {\n _isManager(poolId);\n\n shareClassManager.updateMetadata(poolId, scId, name, symbol);\n }\n\n /// @inheritdoc IHub\n function updateManager(PoolId poolId, address who, bool canManage) external payable {\n _isManager(poolId);\n\n hubRegistry.updateManager(poolId, who, canManage);\n }\n\n /// @inheritdoc IHub\n function addShareClass(PoolId poolId, string calldata name, string calldata symbol, bytes32 salt)\n external\n payable\n returns (ShareClassId scId)\n {\n _isManager(poolId);\n\n return shareClassManager.addShareClass(poolId, name, symbol, salt);\n }\n\n /// @inheritdoc IHub\n function approveDeposits(\n PoolId poolId,\n ShareClassId scId,\n AssetId depositAssetId,\n uint32 nowDepositEpochId,\n uint128 approvedAssetAmount\n ) external payable returns (uint128 pendingAssetAmount, uint128 approvedPoolAmount) {\n _isManagerAndPaid(poolId);\n D18 pricePoolPerAsset = _pricePoolPerAsset(poolId, scId, depositAssetId);\n (pendingAssetAmount, approvedPoolAmount) = shareClassManager.approveDeposits(\n poolId, scId, depositAssetId, nowDepositEpochId, approvedAssetAmount, pricePoolPerAsset\n );\n\n sender.sendApprovedDeposits(poolId, scId, depositAssetId, approvedAssetAmount, pricePoolPerAsset);\n }\n\n /// @inheritdoc IHub\n function approveRedeems(\n PoolId poolId,\n ShareClassId scId,\n AssetId payoutAssetId,\n uint32 nowRedeemEpochId,\n uint128 approvedShareAmount\n ) external payable returns (uint128 pendingShareAmount) {\n _isManager(poolId);\n\n D18 price = _pricePoolPerAsset(poolId, scId, payoutAssetId);\n (pendingShareAmount) =\n shareClassManager.approveRedeems(poolId, scId, payoutAssetId, nowRedeemEpochId, approvedShareAmount, price);\n }\n\n /// @inheritdoc IHub\n function issueShares(\n PoolId poolId,\n ShareClassId scId,\n AssetId depositAssetId,\n uint32 nowIssueEpochId,\n D18 navPoolPerShare\n ) external payable returns (uint128 issuedShareAmount, uint128 depositAssetAmount, uint128 depositPoolAmount) {\n _isManagerAndPaid(poolId);\n\n (issuedShareAmount, depositAssetAmount, depositPoolAmount) =\n shareClassManager.issueShares(poolId, scId, depositAssetId, nowIssueEpochId, navPoolPerShare);\n\n sender.sendIssuedShares(poolId, scId, depositAssetId, issuedShareAmount, navPoolPerShare);\n }\n\n /// @inheritdoc IHub\n function revokeShares(\n PoolId poolId,\n ShareClassId scId,\n AssetId payoutAssetId,\n uint32 nowRevokeEpochId,\n D18 navPoolPerShare\n ) external payable returns (uint128 revokedShareAmount, uint128 payoutAssetAmount, uint128 payoutPoolAmount) {\n _isManagerAndPaid(poolId);\n\n (revokedShareAmount, payoutAssetAmount, payoutPoolAmount) =\n shareClassManager.revokeShares(poolId, scId, payoutAssetId, nowRevokeEpochId, navPoolPerShare);\n\n sender.sendRevokedShares(poolId, scId, payoutAssetId, payoutAssetAmount, revokedShareAmount, navPoolPerShare);\n }\n\n /// @inheritdoc IHub\n function updateRestriction(PoolId poolId, ShareClassId scId, uint16 centrifugeId, bytes calldata payload)\n external\n payable\n {\n _isManagerAndPaid(poolId);\n\n require(shareClassManager.exists(poolId, scId), IShareClassManager.ShareClassNotFound());\n\n emit UpdateRestriction(centrifugeId, poolId, scId, payload);\n sender.sendUpdateRestriction(centrifugeId, poolId, scId, payload);\n }\n\n /// @inheritdoc IHub\n function updateContract(\n PoolId poolId,\n ShareClassId scId,\n uint16 centrifugeId,\n bytes32 target,\n bytes calldata payload\n ) external payable {\n _isManagerAndPaid(poolId);\n\n require(shareClassManager.exists(poolId, scId), IShareClassManager.ShareClassNotFound());\n\n emit UpdateContract(centrifugeId, poolId, scId, target, payload);\n sender.sendUpdateContract(centrifugeId, poolId, scId, target, payload);\n }\n\n /// @inheritdoc IHub\n function updatePricePerShare(PoolId poolId, ShareClassId scId, D18 navPoolPerShare) public payable {\n _isManager(poolId);\n\n shareClassManager.updatePricePerShare(poolId, scId, navPoolPerShare);\n }\n\n /// @inheritdoc IHub\n function createHolding(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n IERC7726 valuation,\n AccountId assetAccount,\n AccountId equityAccount,\n AccountId gainAccount,\n AccountId lossAccount\n ) external payable {\n _isManager(poolId);\n\n require(hubRegistry.isRegistered(assetId), IHubRegistry.AssetNotFound());\n require(\n accounting.exists(poolId, assetAccount) && accounting.exists(poolId, equityAccount)\n && accounting.exists(poolId, lossAccount) && accounting.exists(poolId, gainAccount),\n IAccounting.AccountDoesNotExist()\n );\n\n HoldingAccount[] memory accounts = new HoldingAccount[](4);\n accounts[0] = HoldingAccount(assetAccount, uint8(AccountType.Asset));\n accounts[1] = HoldingAccount(equityAccount, uint8(AccountType.Equity));\n accounts[3] = HoldingAccount(gainAccount, uint8(AccountType.Gain));\n accounts[2] = HoldingAccount(lossAccount, uint8(AccountType.Loss));\n\n holdings.create(poolId, scId, assetId, valuation, false, accounts);\n }\n\n /// @inheritdoc IHub\n function createLiability(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n IERC7726 valuation,\n AccountId expenseAccount,\n AccountId liabilityAccount\n ) external payable {\n _isManager(poolId);\n\n require(hubRegistry.isRegistered(assetId), IHubRegistry.AssetNotFound());\n require(\n accounting.exists(poolId, expenseAccount) && accounting.exists(poolId, liabilityAccount),\n IAccounting.AccountDoesNotExist()\n );\n\n HoldingAccount[] memory accounts = new HoldingAccount[](2);\n accounts[0] = HoldingAccount(expenseAccount, uint8(AccountType.Expense));\n accounts[1] = HoldingAccount(liabilityAccount, uint8(AccountType.Liability));\n\n holdings.create(poolId, scId, assetId, valuation, true, accounts);\n }\n\n /// @inheritdoc IHub\n function updateHoldingValue(PoolId poolId, ShareClassId scId, AssetId assetId) public payable {\n _isManager(poolId);\n\n accounting.unlock(poolId);\n\n (bool isPositive, uint128 diff) = holdings.update(poolId, scId, assetId);\n\n // Save a diff=0 update gas cost\n if (isPositive && diff > 0) {\n if (holdings.isLiability(poolId, scId, assetId)) {\n accounting.addCredit(holdings.accountId(poolId, scId, assetId, uint8(AccountType.Liability)), diff);\n accounting.addDebit(holdings.accountId(poolId, scId, assetId, uint8(AccountType.Expense)), diff);\n } else {\n accounting.addCredit(holdings.accountId(poolId, scId, assetId, uint8(AccountType.Gain)), diff);\n accounting.addDebit(holdings.accountId(poolId, scId, assetId, uint8(AccountType.Asset)), diff);\n }\n } else if (diff > 0) {\n if (holdings.isLiability(poolId, scId, assetId)) {\n accounting.addCredit(holdings.accountId(poolId, scId, assetId, uint8(AccountType.Expense)), diff);\n accounting.addDebit(holdings.accountId(poolId, scId, assetId, uint8(AccountType.Liability)), diff);\n } else {\n accounting.addCredit(holdings.accountId(poolId, scId, assetId, uint8(AccountType.Asset)), diff);\n accounting.addDebit(holdings.accountId(poolId, scId, assetId, uint8(AccountType.Loss)), diff);\n }\n }\n\n accounting.lock();\n }\n\n /// @inheritdoc IHub\n function updateHoldingValuation(PoolId poolId, ShareClassId scId, AssetId assetId, IERC7726 valuation)\n external\n payable\n {\n _isManager(poolId);\n\n holdings.updateValuation(poolId, scId, assetId, valuation);\n }\n\n /// @inheritdoc IHub\n function setHoldingAccountId(PoolId poolId, ShareClassId scId, AssetId assetId, uint8 kind, AccountId accountId)\n external\n payable\n {\n _isManager(poolId);\n\n holdings.setAccountId(poolId, scId, assetId, kind, accountId);\n }\n\n /// @inheritdoc IHub\n function createAccount(PoolId poolId, AccountId account, bool isDebitNormal) public payable {\n _isManager(poolId);\n\n accounting.createAccount(poolId, account, isDebitNormal);\n }\n\n /// @inheritdoc IHub\n function setAccountMetadata(PoolId poolId, AccountId account, bytes calldata metadata) external payable {\n _isManager(poolId);\n\n accounting.setAccountMetadata(poolId, account, metadata);\n }\n\n /// @inheritdoc IHub\n function updateJournal(PoolId poolId, JournalEntry[] memory debits, JournalEntry[] memory credits) external {\n _isManager(poolId);\n\n accounting.unlock(poolId);\n accounting.addJournal(debits, credits);\n accounting.lock();\n }\n\n //----------------------------------------------------------------------------------------------\n // Gateway owner methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHubGatewayHandler\n function registerAsset(AssetId assetId, uint8 decimals) external {\n _auth();\n\n hubRegistry.registerAsset(assetId, decimals);\n }\n\n /// @inheritdoc IHubGatewayHandler\n function depositRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId depositAssetId, uint128 amount)\n external\n {\n _auth();\n\n shareClassManager.requestDeposit(poolId, scId, amount, investor, depositAssetId);\n }\n\n /// @inheritdoc IHubGatewayHandler\n function redeemRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId payoutAssetId, uint128 amount)\n external\n {\n _auth();\n\n shareClassManager.requestRedeem(poolId, scId, amount, investor, payoutAssetId);\n }\n\n /// @inheritdoc IHubGatewayHandler\n function cancelDepositRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId depositAssetId)\n external\n {\n _auth();\n\n uint128 cancelledAssetAmount = shareClassManager.cancelDepositRequest(poolId, scId, investor, depositAssetId);\n\n // Cancellation might have been queued such that it will be executed in the future during claiming\n if (cancelledAssetAmount > 0) {\n sender.sendFulfilledCancelDepositRequest(poolId, scId, depositAssetId, investor, cancelledAssetAmount);\n }\n }\n\n /// @inheritdoc IHubGatewayHandler\n function cancelRedeemRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId payoutAssetId) external {\n _auth();\n\n uint128 cancelledShareAmount = shareClassManager.cancelRedeemRequest(poolId, scId, investor, payoutAssetId);\n\n // Cancellation might have been queued such that it will be executed in the future during claiming\n if (cancelledShareAmount > 0) {\n sender.sendFulfilledCancelRedeemRequest(poolId, scId, payoutAssetId, investor, cancelledShareAmount);\n }\n }\n\n /// @inheritdoc IHubGatewayHandler\n function updateHoldingAmount(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n uint128 amount,\n D18 pricePoolPerAsset,\n bool isIncrease\n ) external {\n _auth();\n\n accounting.unlock(poolId);\n\n bool isLiability = holdings.isLiability(poolId, scId, assetId);\n AccountType debitAccountType = isLiability ? AccountType.Expense : AccountType.Asset;\n AccountType creditAccountType = isLiability ? AccountType.Liability : AccountType.Equity;\n\n if (isIncrease) {\n uint128 value = holdings.increase(poolId, scId, assetId, pricePoolPerAsset, amount);\n accounting.addDebit(holdings.accountId(poolId, scId, assetId, uint8(debitAccountType)), value);\n accounting.addCredit(holdings.accountId(poolId, scId, assetId, uint8(creditAccountType)), value);\n } else {\n uint128 value = holdings.decrease(poolId, scId, assetId, pricePoolPerAsset, amount);\n accounting.addDebit(holdings.accountId(poolId, scId, assetId, uint8(creditAccountType)), value);\n accounting.addCredit(holdings.accountId(poolId, scId, assetId, uint8(debitAccountType)), value);\n }\n\n accounting.lock();\n }\n\n /// @inheritdoc IHubGatewayHandler\n function increaseShareIssuance(PoolId poolId, ShareClassId scId, uint128 amount) external {\n _auth();\n\n shareClassManager.increaseShareClassIssuance(poolId, scId, amount);\n }\n\n /// @inheritdoc IHubGatewayHandler\n function decreaseShareIssuance(PoolId poolId, ShareClassId scId, uint128 amount) external {\n _auth();\n\n shareClassManager.decreaseShareClassIssuance(poolId, scId, amount);\n }\n\n //----------------------------------------------------------------------------------------------\n // Internal methods\n //----------------------------------------------------------------------------------------------\n\n /// @dev Ensure the sender is authorized\n function _auth() internal auth {}\n\n /// @dev Ensure the method can be used without reentrancy issues, and the sender is a pool admin\n function _isManager(PoolId poolId) internal protected {\n require(hubRegistry.manager(poolId, msg.sender), IHub.NotManager());\n }\n\n /// @dev Ensure the sender is authorized\n function _isManagerAndPaid(PoolId poolId) internal {\n _isManager(poolId);\n _pay();\n }\n\n /// @notice Send native tokens to the gateway for transaction payment if it's not in a multicall.\n function _pay() internal {\n if (!gateway.isBatching()) {\n gateway.payTransaction{value: msg.value}(msg.sender);\n }\n }\n\n function _pricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId) internal view returns (D18) {\n AssetId poolCurrency = hubRegistry.currency(poolId);\n // NOTE: We assume symmetric prices are provided by holdings valuation\n IERC7726 valuation = holdings.valuation(poolId, scId, assetId);\n\n // Retrieve amount of 1 asset unit in pool currency\n uint128 assetUnitAmount = (10 ** hubRegistry.decimals(assetId.raw())).toUint128();\n uint128 poolUnitAmount = (10 ** hubRegistry.decimals(poolCurrency.raw())).toUint128();\n uint128 poolAmountPerAsset =\n valuation.getQuote(assetUnitAmount, assetId.addr(), poolCurrency.addr()).toUint128();\n\n // Retrieve price by normalizing by pool denomination\n return d18(poolAmountPerAsset, poolUnitAmount);\n }\n}\n" + }, + "src/hub/HubRegistry.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {IERC6909Decimals} from \"src/misc/interfaces/IERC6909.sol\";\n\nimport {PoolId, newPoolId} from \"src/common/types/PoolId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {IHubRegistry} from \"src/hub/interfaces/IHubRegistry.sol\";\n\n/// @title Hub Registry\n/// @notice Registry of all known pools, currencies, and assets.\ncontract HubRegistry is Auth, IHubRegistry {\n using MathLib for uint256;\n\n mapping(AssetId => uint8) internal _decimals;\n\n mapping(PoolId => bytes) public metadata;\n mapping(PoolId => AssetId) public currency;\n mapping(bytes32 => address) public dependency;\n mapping(PoolId => mapping(address => bool)) public manager;\n\n constructor(address deployer) Auth(deployer) {}\n\n //----------------------------------------------------------------------------------------------\n // Registration methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHubRegistry\n function registerAsset(AssetId assetId, uint8 decimals_) external auth {\n require(_decimals[assetId] == 0, AssetAlreadyRegistered());\n\n _decimals[assetId] = decimals_;\n\n emit NewAsset(assetId, decimals_);\n }\n\n /// @inheritdoc IHubRegistry\n function registerPool(PoolId poolId_, address manager_, AssetId currency_) external auth {\n require(manager_ != address(0), EmptyAccount());\n require(!currency_.isNull(), EmptyCurrency());\n require(currency[poolId_].isNull(), PoolAlreadyRegistered());\n\n manager[poolId_][manager_] = true;\n currency[poolId_] = currency_;\n\n emit NewPool(poolId_, manager_, currency_);\n }\n\n //----------------------------------------------------------------------------------------------\n // Update methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHubRegistry\n function updateManager(PoolId poolId_, address manager_, bool canManage) external auth {\n require(exists(poolId_), NonExistingPool(poolId_));\n require(manager_ != address(0), EmptyAccount());\n\n manager[poolId_][manager_] = canManage;\n\n emit UpdateManager(poolId_, manager_, canManage);\n }\n\n /// @inheritdoc IHubRegistry\n function setMetadata(PoolId poolId_, bytes calldata metadata_) external auth {\n require(exists(poolId_), NonExistingPool(poolId_));\n\n metadata[poolId_] = metadata_;\n\n emit SetMetadata(poolId_, metadata_);\n }\n\n /// @inheritdoc IHubRegistry\n function updateDependency(bytes32 what, address dependency_) external auth {\n dependency[what] = dependency_;\n\n emit UpdateDependency(what, dependency_);\n }\n\n /// @inheritdoc IHubRegistry\n function updateCurrency(PoolId poolId_, AssetId currency_) external auth {\n require(exists(poolId_), NonExistingPool(poolId_));\n require(!currency_.isNull(), EmptyCurrency());\n\n currency[poolId_] = currency_;\n\n emit UpdateCurrency(poolId_, currency_);\n }\n\n //----------------------------------------------------------------------------------------------\n // View methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHubRegistry\n function poolId(uint16 centrifugeId, uint48 postfix) public pure returns (PoolId poolId_) {\n poolId_ = newPoolId(centrifugeId, postfix);\n }\n\n /// @inheritdoc IHubRegistry\n function decimals(AssetId assetId) public view returns (uint8 decimals_) {\n decimals_ = _decimals[assetId];\n require(decimals_ > 0, AssetNotFound());\n }\n\n /// @inheritdoc IHubRegistry\n function decimals(PoolId poolId_) public view returns (uint8 decimals_) {\n decimals_ = _decimals[currency[poolId_]];\n require(decimals_ > 0, AssetNotFound());\n }\n\n /// @inheritdoc IERC6909Decimals\n function decimals(uint256 asset_) external view returns (uint8 decimals_) {\n decimals_ = _decimals[AssetId.wrap(asset_.toUint128())];\n require(decimals_ > 0, AssetNotFound());\n }\n\n /// @inheritdoc IHubRegistry\n function exists(PoolId poolId_) public view returns (bool) {\n return !currency[poolId_].isNull();\n }\n\n /// @inheritdoc IHubRegistry\n function isRegistered(AssetId assetId) public view returns (bool) {\n return _decimals[assetId] != 0;\n }\n}\n" + }, + "src/hub/ShareClassManager.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {D18, d18} from \"src/misc/types/D18.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {ShareClassId, newShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {PricingLib} from \"src/common/libraries/PricingLib.sol\";\n\nimport {IHubRegistry} from \"src/hub/interfaces/IHubRegistry.sol\";\nimport {\n IShareClassManager,\n EpochInvestAmounts,\n EpochRedeemAmounts,\n UserOrder,\n ShareClassMetadata,\n ShareClassMetrics,\n QueuedOrder,\n RequestType,\n EpochId\n} from \"src/hub/interfaces/IShareClassManager.sol\";\n\n/// @title Share Class Manager\n/// @notice Manager for the share classes of a pool, and the core logic for tracking, approving, and fulfilling\n/// requests.\ncontract ShareClassManager is Auth, IShareClassManager {\n using MathLib for *;\n using CastLib for *;\n using BytesLib for bytes;\n\n IHubRegistry public immutable hubRegistry;\n\n // Share classes\n mapping(bytes32 salt => bool) public salts;\n mapping(PoolId poolId => uint32) public shareClassCount;\n mapping(ShareClassId scId => ShareClassMetrics) public metrics;\n mapping(ShareClassId scId => ShareClassMetadata) public metadata;\n mapping(PoolId poolId => mapping(ShareClassId => bool)) public shareClassIds;\n\n // Epochs\n mapping(ShareClassId scId => mapping(AssetId assetId => EpochId)) public epochId;\n mapping(ShareClassId scId => mapping(AssetId assetId => mapping(uint32 epochId_ => EpochInvestAmounts epoch)))\n public epochInvestAmounts;\n mapping(ShareClassId scId => mapping(AssetId assetId => mapping(uint32 epochId_ => EpochRedeemAmounts epoch)))\n public epochRedeemAmounts;\n\n // Pending requests\n mapping(ShareClassId scId => mapping(AssetId payoutAssetId => uint128 pending)) public pendingRedeem;\n mapping(ShareClassId scId => mapping(AssetId depositAssetId => uint128 pending)) public pendingDeposit;\n mapping(ShareClassId scId => mapping(AssetId payoutAssetId => mapping(bytes32 investor => UserOrder pending)))\n public redeemRequest;\n mapping(ShareClassId scId => mapping(AssetId depositAssetId => mapping(bytes32 investor => UserOrder pending)))\n public depositRequest;\n\n // Queued requests\n mapping(ShareClassId scId => mapping(AssetId payoutAssetId => mapping(bytes32 investor => QueuedOrder queued)))\n public queuedRedeemRequest;\n mapping(ShareClassId scId => mapping(AssetId depositAssetId => mapping(bytes32 investor => QueuedOrder queued)))\n public queuedDepositRequest;\n\n constructor(IHubRegistry hubRegistry_, address deployer) Auth(deployer) {\n hubRegistry = hubRegistry_;\n }\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IShareClassManager\n function addShareClass(PoolId poolId, string calldata name, string calldata symbol, bytes32 salt)\n external\n auth\n returns (ShareClassId scId_)\n {\n scId_ = previewNextShareClassId(poolId);\n\n uint32 index = ++shareClassCount[poolId];\n shareClassIds[poolId][scId_] = true;\n\n _updateMetadata(scId_, name, symbol, salt);\n\n emit AddShareClass(poolId, scId_, index, name, symbol, salt);\n }\n\n //----------------------------------------------------------------------------------------------\n // Incoming requests\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IShareClassManager\n function requestDeposit(PoolId poolId, ShareClassId scId_, uint128 amount, bytes32 investor, AssetId depositAssetId)\n external\n auth\n {\n require(exists(poolId, scId_), ShareClassNotFound());\n\n // NOTE: CV ensures amount > 0\n _updatePending(poolId, scId_, amount, true, investor, depositAssetId, RequestType.Deposit);\n }\n\n /// @inheritdoc IShareClassManager\n function cancelDepositRequest(PoolId poolId, ShareClassId scId_, bytes32 investor, AssetId depositAssetId)\n external\n auth\n returns (uint128 cancelledAssetAmount)\n {\n require(exists(poolId, scId_), ShareClassNotFound());\n\n uint128 cancellingAmount = depositRequest[scId_][depositAssetId][investor].pending;\n\n return _updatePending(poolId, scId_, cancellingAmount, false, investor, depositAssetId, RequestType.Deposit);\n }\n\n /// @inheritdoc IShareClassManager\n function requestRedeem(PoolId poolId, ShareClassId scId_, uint128 amount, bytes32 investor, AssetId payoutAssetId)\n external\n auth\n {\n require(exists(poolId, scId_), ShareClassNotFound());\n\n // NOTE: CV ensures amount > 0\n _updatePending(poolId, scId_, amount, true, investor, payoutAssetId, RequestType.Redeem);\n }\n\n /// @inheritdoc IShareClassManager\n function cancelRedeemRequest(PoolId poolId, ShareClassId scId_, bytes32 investor, AssetId payoutAssetId)\n external\n auth\n returns (uint128 cancelledShareAmount)\n {\n require(exists(poolId, scId_), ShareClassNotFound());\n\n uint128 cancellingAmount = redeemRequest[scId_][payoutAssetId][investor].pending;\n\n return _updatePending(poolId, scId_, cancellingAmount, false, investor, payoutAssetId, RequestType.Redeem);\n }\n\n //----------------------------------------------------------------------------------------------\n // Manager actions\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IShareClassManager\n function approveDeposits(\n PoolId poolId,\n ShareClassId scId_,\n AssetId depositAssetId,\n uint32 nowDepositEpochId,\n uint128 approvedAssetAmount,\n D18 pricePoolPerAsset\n ) external auth returns (uint128 pendingAssetAmount, uint128 approvedPoolAmount) {\n require(exists(poolId, scId_), ShareClassNotFound());\n require(\n nowDepositEpochId == nowDepositEpoch(scId_, depositAssetId),\n EpochNotInSequence(nowDepositEpochId, nowDepositEpoch(scId_, depositAssetId))\n );\n\n // Limit in case approved > pending due to race condition of FM approval and async incoming requests\n pendingAssetAmount = pendingDeposit[scId_][depositAssetId];\n require(approvedAssetAmount <= pendingAssetAmount, InsufficientPending());\n require(approvedAssetAmount > 0, ZeroApprovalAmount());\n\n approvedPoolAmount = PricingLib.convertWithPrice(\n approvedAssetAmount, hubRegistry.decimals(depositAssetId), hubRegistry.decimals(poolId), pricePoolPerAsset\n ).toUint128();\n\n // Update epoch data\n EpochInvestAmounts storage epochAmounts = epochInvestAmounts[scId_][depositAssetId][nowDepositEpochId];\n epochAmounts.approvedAssetAmount = approvedAssetAmount;\n epochAmounts.approvedPoolAmount = approvedPoolAmount;\n epochAmounts.pendingAssetAmount = pendingAssetAmount;\n epochAmounts.pricePoolPerAsset = pricePoolPerAsset;\n\n // Reduce pending\n pendingDeposit[scId_][depositAssetId] -= approvedAssetAmount;\n pendingAssetAmount -= approvedAssetAmount;\n\n epochId[scId_][depositAssetId].deposit = nowDepositEpochId;\n emit ApproveDeposits(\n poolId,\n scId_,\n depositAssetId,\n nowDepositEpochId,\n approvedPoolAmount,\n approvedAssetAmount,\n pendingAssetAmount\n );\n }\n\n /// @inheritdoc IShareClassManager\n function approveRedeems(\n PoolId poolId,\n ShareClassId scId_,\n AssetId payoutAssetId,\n uint32 nowRedeemEpochId,\n uint128 approvedShareAmount,\n D18 pricePoolPerAsset\n ) external auth returns (uint128 pendingShareAmount) {\n require(exists(poolId, scId_), ShareClassNotFound());\n require(\n nowRedeemEpochId == nowRedeemEpoch(scId_, payoutAssetId),\n EpochNotInSequence(nowRedeemEpochId, nowRedeemEpoch(scId_, payoutAssetId))\n );\n\n // Limit in case approved > pending due to race condition of FM approval and async incoming requests\n pendingShareAmount = pendingRedeem[scId_][payoutAssetId];\n require(approvedShareAmount <= pendingShareAmount, InsufficientPending());\n require(approvedShareAmount > 0, ZeroApprovalAmount());\n\n // Update epoch data\n EpochRedeemAmounts storage epochAmounts = epochRedeemAmounts[scId_][payoutAssetId][nowRedeemEpochId];\n epochAmounts.approvedShareAmount = approvedShareAmount;\n epochAmounts.pendingShareAmount = pendingShareAmount;\n epochAmounts.pricePoolPerAsset = pricePoolPerAsset;\n\n // Reduce pending\n pendingRedeem[scId_][payoutAssetId] -= approvedShareAmount;\n pendingShareAmount -= approvedShareAmount;\n epochId[scId_][payoutAssetId].redeem = nowRedeemEpochId;\n emit ApproveRedeems(poolId, scId_, payoutAssetId, nowRedeemEpochId, approvedShareAmount, pendingShareAmount);\n }\n\n /// @inheritdoc IShareClassManager\n function issueShares(\n PoolId poolId,\n ShareClassId scId_,\n AssetId depositAssetId,\n uint32 nowIssueEpochId,\n D18 navPoolPerShare\n ) external auth returns (uint128 issuedShareAmount, uint128 depositAssetAmount, uint128 depositPoolAmount) {\n require(exists(poolId, scId_), ShareClassNotFound());\n require(nowIssueEpochId <= epochId[scId_][depositAssetId].deposit, EpochNotFound());\n require(\n nowIssueEpochId == nowIssueEpoch(scId_, depositAssetId),\n EpochNotInSequence(nowIssueEpochId, nowIssueEpoch(scId_, depositAssetId))\n );\n\n EpochInvestAmounts storage epochAmounts = epochInvestAmounts[scId_][depositAssetId][nowIssueEpochId];\n epochAmounts.navPoolPerShare = navPoolPerShare;\n\n issuedShareAmount = PricingLib.assetToShareAmount(\n epochAmounts.approvedAssetAmount,\n hubRegistry.decimals(depositAssetId),\n hubRegistry.decimals(poolId),\n epochAmounts.pricePoolPerAsset,\n navPoolPerShare,\n MathLib.Rounding.Down\n ).toUint128();\n\n metrics[scId_].totalIssuance += issuedShareAmount;\n epochAmounts.issuedAt = block.timestamp.toUint64();\n epochId[scId_][depositAssetId].issue = nowIssueEpochId;\n\n depositAssetAmount = epochAmounts.approvedAssetAmount;\n depositPoolAmount = epochAmounts.approvedPoolAmount;\n\n emit IssueShares(\n poolId,\n scId_,\n depositAssetId,\n nowIssueEpochId,\n navPoolPerShare,\n PricingLib.priceAssetPerShare(epochAmounts.navPoolPerShare, epochAmounts.pricePoolPerAsset),\n issuedShareAmount\n );\n }\n\n /// @inheritdoc IShareClassManager\n function revokeShares(\n PoolId poolId,\n ShareClassId scId_,\n AssetId payoutAssetId,\n uint32 nowRevokeEpochId,\n D18 navPoolPerShare\n ) external auth returns (uint128 revokedShareAmount, uint128 payoutAssetAmount, uint128 payoutPoolAmount) {\n require(exists(poolId, scId_), ShareClassNotFound());\n require(nowRevokeEpochId <= epochId[scId_][payoutAssetId].redeem, EpochNotFound());\n require(\n nowRevokeEpochId == nowRevokeEpoch(scId_, payoutAssetId),\n EpochNotInSequence(nowRevokeEpochId, nowRevokeEpoch(scId_, payoutAssetId))\n );\n\n EpochRedeemAmounts storage epochAmounts = epochRedeemAmounts[scId_][payoutAssetId][nowRevokeEpochId];\n epochAmounts.navPoolPerShare = navPoolPerShare;\n\n require(epochAmounts.approvedShareAmount <= metrics[scId_].totalIssuance, RevokeMoreThanIssued());\n\n // NOTE: shares and pool currency have the same decimals - no conversion needed!\n payoutPoolAmount = navPoolPerShare.mulUint128(epochAmounts.approvedShareAmount, MathLib.Rounding.Down);\n\n payoutAssetAmount = PricingLib.poolToAssetAmount(\n payoutPoolAmount,\n hubRegistry.decimals(poolId),\n hubRegistry.decimals(payoutAssetId),\n epochAmounts.pricePoolPerAsset,\n MathLib.Rounding.Down\n ).toUint128();\n revokedShareAmount = epochAmounts.approvedShareAmount;\n\n metrics[scId_].totalIssuance -= epochAmounts.approvedShareAmount;\n epochAmounts.payoutAssetAmount = payoutAssetAmount;\n epochAmounts.revokedAt = block.timestamp.toUint64();\n epochId[scId_][payoutAssetId].revoke = nowRevokeEpochId;\n\n emit RevokeShares(\n poolId,\n scId_,\n payoutAssetId,\n nowRevokeEpochId,\n navPoolPerShare,\n PricingLib.priceAssetPerShare(epochAmounts.navPoolPerShare, epochAmounts.pricePoolPerAsset),\n epochAmounts.approvedShareAmount,\n payoutAssetAmount,\n payoutPoolAmount\n );\n }\n\n /// @inheritdoc IShareClassManager\n function updatePricePerShare(PoolId poolId, ShareClassId scId_, D18 navPoolPerShare) external auth {\n require(exists(poolId, scId_), ShareClassNotFound());\n\n ShareClassMetrics storage m = metrics[scId_];\n m.navPerShare = navPoolPerShare;\n emit UpdateShareClass(poolId, scId_, navPoolPerShare);\n }\n\n /// @inheritdoc IShareClassManager\n function updateMetadata(PoolId poolId, ShareClassId scId_, string calldata name, string calldata symbol)\n external\n auth\n {\n require(exists(poolId, scId_), ShareClassNotFound());\n\n _updateMetadata(scId_, name, symbol, bytes32(0));\n\n emit UpdateMetadata(poolId, scId_, name, symbol);\n }\n\n /// @inheritdoc IShareClassManager\n function increaseShareClassIssuance(PoolId poolId, ShareClassId scId_, uint128 amount) external auth {\n require(exists(poolId, scId_), ShareClassNotFound());\n\n uint128 newIssuance = metrics[scId_].totalIssuance + amount;\n metrics[scId_].totalIssuance = newIssuance;\n\n emit RemoteIssueShares(poolId, scId_, amount);\n }\n\n /// @inheritdoc IShareClassManager\n function decreaseShareClassIssuance(PoolId poolId, ShareClassId scId_, uint128 amount) external auth {\n require(exists(poolId, scId_), ShareClassNotFound());\n require(metrics[scId_].totalIssuance >= amount, DecreaseMoreThanIssued());\n\n uint128 newIssuance = metrics[scId_].totalIssuance - amount;\n metrics[scId_].totalIssuance = newIssuance;\n\n emit RemoteRevokeShares(poolId, scId_, amount);\n }\n\n //----------------------------------------------------------------------------------------------\n // Claiming methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IShareClassManager\n function claimDeposit(PoolId poolId, ShareClassId scId_, bytes32 investor, AssetId depositAssetId)\n public\n auth\n returns (\n uint128 payoutShareAmount,\n uint128 paymentAssetAmount,\n uint128 cancelledAssetAmount,\n bool canClaimAgain\n )\n {\n require(exists(poolId, scId_), ShareClassNotFound());\n\n UserOrder storage userOrder = depositRequest[scId_][depositAssetId][investor];\n require(userOrder.pending > 0, NoOrderFound());\n require(userOrder.lastUpdate <= epochId[scId_][depositAssetId].issue, IssuanceRequired());\n canClaimAgain = userOrder.lastUpdate < epochId[scId_][depositAssetId].issue;\n EpochInvestAmounts storage epochAmounts = epochInvestAmounts[scId_][depositAssetId][userOrder.lastUpdate];\n\n paymentAssetAmount = epochAmounts.approvedAssetAmount == 0\n ? 0\n : userOrder.pending.mulDiv(epochAmounts.approvedAssetAmount, epochAmounts.pendingAssetAmount).toUint128();\n\n // NOTE: Due to precision loss, the sum of claimable user amounts is leq than the amount of minted share class\n // tokens corresponding to the approved share amount (instead of equality). I.e., it is possible for an epoch to\n // have an excess of a share class tokens which cannot be claimed by anyone.\n // This excess is at most n-1 share tokens for an epoch with n claimable users.\n if (paymentAssetAmount > 0) {\n uint256 paymentPoolAmount = PricingLib.convertWithPrice(\n paymentAssetAmount,\n hubRegistry.decimals(depositAssetId),\n hubRegistry.decimals(poolId),\n epochAmounts.pricePoolPerAsset\n );\n payoutShareAmount =\n epochAmounts.navPoolPerShare.reciprocalMulUint256(paymentPoolAmount, MathLib.Rounding.Down).toUint128();\n\n userOrder.pending -= paymentAssetAmount;\n }\n\n emit ClaimDeposit(\n poolId,\n scId_,\n userOrder.lastUpdate,\n investor,\n depositAssetId,\n paymentAssetAmount,\n userOrder.pending,\n payoutShareAmount,\n epochAmounts.issuedAt\n );\n\n // If there is nothing to claim anymore we can short circuit to the latest epoch\n if (userOrder.pending == 0) {\n // The current epoch is always one step ahead of the stored one\n userOrder.lastUpdate = nowDepositEpoch(scId_, depositAssetId);\n canClaimAgain = false;\n } else {\n userOrder.lastUpdate += 1;\n }\n\n // If user claimed up to latest approval epoch, move queued to pending\n if (userOrder.lastUpdate == nowDepositEpoch(scId_, depositAssetId)) {\n cancelledAssetAmount =\n _postClaimUpdateQueued(poolId, scId_, investor, depositAssetId, userOrder, RequestType.Deposit);\n }\n }\n\n /// @inheritdoc IShareClassManager\n function claimRedeem(PoolId poolId, ShareClassId scId_, bytes32 investor, AssetId payoutAssetId)\n public\n auth\n returns (\n uint128 payoutAssetAmount,\n uint128 paymentShareAmount,\n uint128 cancelledShareAmount,\n bool canClaimAgain\n )\n {\n require(exists(poolId, scId_), ShareClassNotFound());\n\n UserOrder storage userOrder = redeemRequest[scId_][payoutAssetId][investor];\n require(userOrder.pending > 0, NoOrderFound());\n require(userOrder.lastUpdate <= epochId[scId_][payoutAssetId].revoke, RevocationRequired());\n canClaimAgain = userOrder.lastUpdate < epochId[scId_][payoutAssetId].revoke;\n\n EpochRedeemAmounts storage epochAmounts = epochRedeemAmounts[scId_][payoutAssetId][userOrder.lastUpdate];\n\n paymentShareAmount = epochAmounts.approvedShareAmount == 0\n ? 0\n : userOrder.pending.mulDiv(epochAmounts.approvedShareAmount, epochAmounts.pendingShareAmount).toUint128();\n\n // NOTE: Due to precision loss, the sum of claimable user amounts is leq than the amount of minted share class\n // tokens corresponding to the approved share amount (instead of equality). I.e., it is possible for an epoch to\n // have an excess of a share class tokens which cannot be claimed by anyone.\n // This excess is at most n-1 share tokens for an epoch with n claimable users.\n if (paymentShareAmount > 0) {\n payoutAssetAmount = PricingLib.shareToAssetAmount(\n paymentShareAmount,\n hubRegistry.decimals(poolId),\n hubRegistry.decimals(payoutAssetId),\n epochAmounts.pricePoolPerAsset,\n epochAmounts.navPoolPerShare,\n MathLib.Rounding.Down\n ).toUint128();\n\n userOrder.pending -= paymentShareAmount;\n }\n\n emit ClaimRedeem(\n poolId,\n scId_,\n userOrder.lastUpdate,\n investor,\n payoutAssetId,\n paymentShareAmount,\n userOrder.pending,\n payoutAssetAmount,\n epochAmounts.revokedAt\n );\n\n // If there is nothing to claim anymore we can short circuit the in between epochs\n if (userOrder.pending == 0) {\n // The current epoch is always one step ahead of the stored one\n userOrder.lastUpdate = nowRedeemEpoch(scId_, payoutAssetId);\n canClaimAgain = false;\n } else {\n userOrder.lastUpdate += 1;\n }\n\n if (userOrder.lastUpdate == nowRedeemEpoch(scId_, payoutAssetId)) {\n cancelledShareAmount =\n _postClaimUpdateQueued(poolId, scId_, investor, payoutAssetId, userOrder, RequestType.Redeem);\n }\n }\n\n //----------------------------------------------------------------------------------------------\n // View methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IShareClassManager\n function previewNextShareClassId(PoolId poolId) public view returns (ShareClassId scId) {\n return newShareClassId(poolId, shareClassCount[poolId] + 1);\n }\n\n /// @inheritdoc IShareClassManager\n function previewShareClassId(PoolId poolId, uint32 index) public pure returns (ShareClassId scId) {\n return newShareClassId(poolId, index);\n }\n\n /// @inheritdoc IShareClassManager\n function exists(PoolId poolId, ShareClassId scId_) public view returns (bool) {\n return shareClassIds[poolId][scId_];\n }\n\n /// @inheritdoc IShareClassManager\n function nowDepositEpoch(ShareClassId scId_, AssetId depositAssetId) public view returns (uint32) {\n return epochId[scId_][depositAssetId].deposit + 1;\n }\n\n /// @inheritdoc IShareClassManager\n function nowIssueEpoch(ShareClassId scId_, AssetId depositAssetId) public view returns (uint32) {\n return epochId[scId_][depositAssetId].issue + 1;\n }\n\n /// @inheritdoc IShareClassManager\n function nowRedeemEpoch(ShareClassId scId_, AssetId depositAssetId) public view returns (uint32) {\n return epochId[scId_][depositAssetId].redeem + 1;\n }\n\n /// @inheritdoc IShareClassManager\n function nowRevokeEpoch(ShareClassId scId_, AssetId depositAssetId) public view returns (uint32) {\n return epochId[scId_][depositAssetId].revoke + 1;\n }\n\n /// @inheritdoc IShareClassManager\n function maxDepositClaims(ShareClassId scId_, bytes32 investor, AssetId depositAssetId)\n public\n view\n returns (uint32)\n {\n return _maxClaims(depositRequest[scId_][depositAssetId][investor], epochId[scId_][depositAssetId].deposit);\n }\n\n /// @inheritdoc IShareClassManager\n function maxRedeemClaims(ShareClassId scId_, bytes32 investor, AssetId payoutAssetId)\n public\n view\n returns (uint32)\n {\n return _maxClaims(redeemRequest[scId_][payoutAssetId][investor], epochId[scId_][payoutAssetId].redeem);\n }\n\n function _maxClaims(UserOrder memory userOrder, uint32 lastEpoch) private pure returns (uint32) {\n // User order either not set or not processed\n if (userOrder.pending == 0 || userOrder.lastUpdate > lastEpoch) {\n return 0;\n }\n\n return lastEpoch - userOrder.lastUpdate + 1;\n }\n\n //----------------------------------------------------------------------------------------------\n // Internal methods\n //----------------------------------------------------------------------------------------------\n\n function _updateMetadata(ShareClassId scId_, string calldata name, string calldata symbol, bytes32 salt) private {\n uint256 nameLen = bytes(name).length;\n require(nameLen > 0 && nameLen <= 128, InvalidMetadataName());\n\n uint256 symbolLen = bytes(symbol).length;\n require(symbolLen > 0 && symbolLen <= 32, InvalidMetadataSymbol());\n\n ShareClassMetadata storage meta = metadata[scId_];\n\n // Ensure that the salt is not being updated or is being set for the first time\n require(\n (salt == bytes32(0) && meta.salt != bytes32(0)) || (salt != bytes32(0) && meta.salt == bytes32(0)),\n InvalidSalt()\n );\n\n if (salt != bytes32(0) && meta.salt == bytes32(0)) {\n require(!salts[salt], AlreadyUsedSalt());\n salts[salt] = true;\n meta.salt = salt;\n }\n\n meta.name = name;\n meta.symbol = symbol;\n }\n\n function _postClaimUpdateQueued(\n PoolId poolId,\n ShareClassId scId_,\n bytes32 investor,\n AssetId assetId,\n UserOrder storage userOrder,\n RequestType requestType\n ) private returns (uint128 cancelledAmount) {\n QueuedOrder storage queued = requestType == RequestType.Deposit\n ? queuedDepositRequest[scId_][assetId][investor]\n : queuedRedeemRequest[scId_][assetId][investor];\n\n // Increment pending by queued or cancel everything\n uint128 updatePendingAmount = queued.isCancelling ? userOrder.pending : queued.amount;\n if (queued.isCancelling) {\n cancelledAmount = userOrder.pending + queued.amount;\n userOrder.pending = 0;\n } else {\n userOrder.pending += queued.amount;\n }\n\n if (requestType == RequestType.Deposit) {\n _updatePendingDeposit(\n poolId,\n scId_,\n updatePendingAmount,\n !queued.isCancelling,\n investor,\n assetId,\n userOrder,\n QueuedOrder(false, 0)\n );\n } else {\n _updatePendingRedeem(\n poolId,\n scId_,\n updatePendingAmount,\n !queued.isCancelling,\n investor,\n assetId,\n userOrder,\n QueuedOrder(false, 0)\n );\n }\n\n // Clear queued\n queued.isCancelling = false;\n queued.amount = 0;\n }\n\n /// @notice Updates the amount of a deposit or redeem request.\n ///\n /// @param poolId Identifier of the pool\n /// @param scId_ Identifier of the share class\n /// @param amount Amount which is updated\n /// @param isIncrement Whether the amount is positive (additional request) or negative (cancellation)\n /// @param investor Address of the entity which is depositing\n /// @param assetId Identifier of the asset which the investor either used as deposit or wants to redeem to\n /// @param requestType Flag indicating whether the request is a deposit or redeem request\n /// @return cancelledAmount Pending amount which was cancelled\n function _updatePending(\n PoolId poolId,\n ShareClassId scId_,\n uint128 amount,\n bool isIncrement,\n bytes32 investor,\n AssetId assetId,\n RequestType requestType\n ) private returns (uint128 cancelledAmount) {\n UserOrder storage userOrder = requestType == RequestType.Deposit\n ? depositRequest[scId_][assetId][investor]\n : redeemRequest[scId_][assetId][investor];\n QueuedOrder storage queued = requestType == RequestType.Deposit\n ? queuedDepositRequest[scId_][assetId][investor]\n : queuedRedeemRequest[scId_][assetId][investor];\n\n // We must only update either queued or pending\n if (_updateQueued(poolId, scId_, amount, isIncrement, investor, assetId, userOrder, queued, requestType)) {\n return 0;\n }\n\n cancelledAmount = isIncrement ? 0 : amount;\n // NOTE: If we decrease the pending, we decrease usually by the full amount\n // We keep subtraction of amount over setting to zero on purpose to not limit future higher level logic\n userOrder.pending = isIncrement ? userOrder.pending + amount : userOrder.pending - amount;\n\n userOrder.lastUpdate =\n requestType == RequestType.Deposit ? nowDepositEpoch(scId_, assetId) : nowRedeemEpoch(scId_, assetId);\n\n if (requestType == RequestType.Deposit) {\n _updatePendingDeposit(poolId, scId_, amount, isIncrement, investor, assetId, userOrder, queued);\n } else {\n _updatePendingRedeem(poolId, scId_, amount, isIncrement, investor, assetId, userOrder, queued);\n }\n }\n\n /// @notice Checks whether the pending amount can be updated. If not, it updates the queued amount.\n ///\n /// @param poolId Identifier of the pool\n /// @param scId_ Identifier of the share class\n /// @param amount Amount which is updated\n /// @param isIncrement Whether the amount is positive (additional request) or negative (cancellation)\n /// @param investor Address of the entity which is depositing\n /// @param assetId Identifier of the asset which the investor either used as deposit or wants to redeem to\n /// @param userOrder User order storage for the deposit or redeem request\n /// @param requestType Flag indicating whether the request is a deposit or redeem request\n /// @return skipPendingUpdate Flag indicating whether the pending amount can be updated which is true if the user\n /// does not need to claim\n function _updateQueued(\n PoolId poolId,\n ShareClassId scId_,\n uint128 amount,\n bool isIncrement,\n bytes32 investor,\n AssetId assetId,\n UserOrder storage userOrder,\n QueuedOrder storage queued,\n RequestType requestType\n ) private returns (bool skipPendingUpdate) {\n uint32 lastEpoch =\n requestType == RequestType.Deposit ? epochId[scId_][assetId].deposit : epochId[scId_][assetId].redeem;\n uint32 currentEpoch = lastEpoch + 1;\n\n // Short circuit if user can mutate pending, i.e. last update happened after latest approval or is first update\n if (userOrder.lastUpdate == currentEpoch || userOrder.pending == 0 || lastEpoch == 0) {\n return false;\n }\n\n // Block increasing queued amount if cancelling is already queued\n // NOTE: Can only happen due to race condition as CV blocks requests if cancellation is in progress\n require(!(queued.isCancelling && amount > 0), CancellationQueued());\n\n if (!isIncrement) {\n queued.isCancelling = true;\n } else {\n queued.amount += amount;\n }\n\n if (requestType == RequestType.Deposit) {\n uint128 pendingTotal = pendingDeposit[scId_][assetId];\n emit UpdateDepositRequest(\n poolId,\n scId_,\n assetId,\n currentEpoch,\n investor,\n userOrder.pending,\n pendingTotal,\n queued.amount,\n queued.isCancelling\n );\n } else {\n uint128 pendingTotal = pendingRedeem[scId_][assetId];\n\n emit UpdateRedeemRequest(\n poolId,\n scId_,\n assetId,\n currentEpoch,\n investor,\n userOrder.pending,\n pendingTotal,\n queued.amount,\n queued.isCancelling\n );\n }\n\n return true;\n }\n\n function _updatePendingDeposit(\n PoolId poolId,\n ShareClassId scId_,\n uint128 amount,\n bool isIncrement,\n bytes32 investor,\n AssetId assetId,\n UserOrder storage userOrder,\n QueuedOrder memory queued\n ) private {\n uint128 pendingTotal = pendingDeposit[scId_][assetId];\n pendingTotal = isIncrement ? pendingTotal + amount : pendingTotal - amount;\n pendingDeposit[scId_][assetId] = pendingTotal;\n\n emit UpdateDepositRequest(\n poolId,\n scId_,\n assetId,\n nowDepositEpoch(scId_, assetId),\n investor,\n userOrder.pending,\n pendingTotal,\n queued.amount,\n queued.isCancelling\n );\n }\n\n function _updatePendingRedeem(\n PoolId poolId,\n ShareClassId scId_,\n uint128 amount,\n bool isIncrement,\n bytes32 investor,\n AssetId assetId,\n UserOrder storage userOrder,\n QueuedOrder memory queued\n ) private {\n uint128 pendingTotal = pendingRedeem[scId_][assetId];\n pendingTotal = isIncrement ? pendingTotal + amount : pendingTotal - amount;\n pendingRedeem[scId_][assetId] = pendingTotal;\n\n emit UpdateRedeemRequest(\n poolId,\n scId_,\n assetId,\n nowRedeemEpoch(scId_, assetId),\n investor,\n userOrder.pending,\n pendingTotal,\n queued.amount,\n queued.isCancelling\n );\n }\n}\n" + }, + "src/hub/interfaces/IAccounting.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {AccountId} from \"src/common/types/AccountId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\n\nstruct JournalEntry {\n uint128 value;\n AccountId accountId;\n}\n\ninterface IAccounting {\n /// @notice Emitted when a an entry is done\n event Credit(PoolId indexed poolId, AccountId indexed account, uint128 value);\n event Debit(PoolId indexed poolId, AccountId indexed account, uint128 value);\n\n /// @notice Emitted at the beginning and end of a journal entry\n event StartJournalId(PoolId indexed poolId, uint256 journalId);\n event EndJournalId(PoolId indexed poolId, uint256 journalId);\n\n /// @notice Emitted when a new account is created\n event CreateAccount(PoolId indexed poolId, AccountId indexed account, bool isDebitNormal);\n\n /// @notice Emitted when metadata is set for an account\n event SetAccountMetadata(PoolId indexed poolId, AccountId indexed account, bytes metadata);\n\n /// @notice Dispatched when the pool is already unlocked.\n error AccountingAlreadyUnlocked();\n\n /// @notice Dispatched when the pool is not unlocked to interact with.\n error AccountingLocked();\n\n /// @notice Dispatched when the debit and credit side do not match at the end of a transaction.\n error Unbalanced();\n\n /// @notice Dispatched when trying to create an account that already exists.\n error AccountExists();\n\n /// @notice Dispatched when trying debit or credit an account that doesn't exists.\n error AccountDoesNotExist();\n\n /// @notice Represents an account\n struct Account {\n uint128 totalDebit;\n uint128 totalCredit;\n bool isDebitNormal;\n uint64 lastUpdated;\n bytes metadata;\n }\n\n /// @notice Debits an account. Increase the value of debit-normal accounts, decrease for credit-normal ones.\n /// @param account The account to debit\n /// @param value Amount being debited\n function addDebit(AccountId account, uint128 value) external;\n\n /// @notice Credits an account. Decrease the value of debit-normal accounts, increase for credit-normal ones.\n /// @param account The account to credit\n /// @param value Amount being credited\n function addCredit(AccountId account, uint128 value) external;\n\n /// @notice Apply addDebit and addCredit to each journal entry\n function addJournal(JournalEntry[] memory debits, JournalEntry[] memory credits) external;\n\n /// @notice Unlocks a pool for journal entries\n /// @param poolId The pool to unlock\n function unlock(PoolId poolId) external;\n\n /// @notice Closes the transaction and checks if the entries are balanced.\n function lock() external;\n\n /// @notice Creates an account.\n /// @param poolId The pool the account belongs to\n /// @param account The account to create\n /// @param isDebitNormal Whether the account is debit-normal or credit-normal\n function createAccount(PoolId poolId, AccountId account, bool isDebitNormal) external;\n\n /// @notice Sets metadata associated to an existent account.\n /// @param poolId The pool the account belongs to\n /// @param account The account to set metadata for\n /// @param metadata The metadata to set\n function setAccountMetadata(PoolId poolId, AccountId account, bytes calldata metadata) external;\n\n /// @notice Returns the value of an account\n /// @param poolId The pool the account belongs to\n /// @param account The account to get the value of\n /// @return isPositive Indicates whether value is a positive or negative value\n /// @return value The value of the account\n function accountValue(PoolId poolId, AccountId account) external view returns (bool isPositive, uint128 value);\n\n /// @notice Returns whether an account exists\n /// @param poolId The pool the account belongs to\n /// @param account The account to check\n /// @return True if the account exists, false otherwise\n function exists(PoolId poolId, AccountId account) external view returns (bool);\n}\n" + }, + "src/hub/interfaces/IHoldings.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IERC7726} from \"src/misc/interfaces/IERC7726.sol\";\nimport {D18} from \"src/misc/types/D18.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {AccountId} from \"src/common/types/AccountId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nstruct Holding {\n uint128 assetAmount;\n uint128 assetAmountValue;\n IERC7726 valuation; // Used for existence\n bool isLiability;\n}\n\nstruct HoldingAccount {\n AccountId accountId;\n uint8 kind;\n}\n\ninterface IHoldings {\n /// @notice Emitted when a holding is created\n event Create(\n PoolId indexed,\n ShareClassId indexed scId,\n AssetId indexed assetId,\n IERC7726 valuation,\n bool isLiability,\n HoldingAccount[] accounts\n );\n\n /// @notice Emitted when a holding is increased\n event Increase(\n PoolId indexed,\n ShareClassId indexed scId,\n AssetId indexed assetId,\n D18 pricePoolPerAsset,\n uint128 amount,\n uint128 increasedValue\n );\n\n /// @notice Emitted when a holding is decreased\n event Decrease(\n PoolId indexed,\n ShareClassId indexed scId,\n AssetId indexed assetId,\n D18 pricePoolPerAsset,\n uint128 amount,\n uint128 decreasedValue\n );\n\n /// @notice Emitted when the holding is updated\n event Update(\n PoolId indexed, ShareClassId indexed scId, AssetId indexed assetId, bool isPositive, uint128 diffValue\n );\n\n /// @notice Emitted when a holding valuation is updated\n event UpdateValuation(PoolId indexed, ShareClassId indexed scId, AssetId indexed assetId, IERC7726 valuation);\n\n /// @notice Emitted when an account is for a holding is set\n event SetAccountId(\n PoolId indexed, ShareClassId indexed scId, AssetId indexed assetId, uint8 kind, AccountId accountId\n );\n\n /// @notice Item was not found for a required action\n error HoldingNotFound();\n\n /// @notice Valuation is not valid.\n error WrongValuation();\n\n /// @notice ShareClassId is not valid.\n error WrongShareClassId();\n\n /// @notice AssetId is not valid.\n error WrongAssetId();\n\n /// @notice Creates a new holding in a pool using a valuation\n function create(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n IERC7726 valuation,\n bool isLiability,\n HoldingAccount[] memory accounts\n ) external;\n\n /// @notice Increments the amount of a holding and updates the value for that increment.\n /// @return value The value the holding has increment.\n function increase(PoolId poolId, ShareClassId scId, AssetId assetId, D18 pricePoolPerAsset, uint128 amount)\n external\n returns (uint128 value);\n\n /// @notice Decrements the amount of a holding and updates the value for that decrement.\n /// @return value The value the holding has decrement.\n function decrease(PoolId poolId, ShareClassId scId, AssetId assetId, D18 pricePoolPerAsset, uint128 amount)\n external\n returns (uint128 value);\n\n /// @notice Reset the value of a holding using the current valuation.\n /// @return isPositive Indicates whether the diffValue is positive or negative\n /// @return diffValue The difference in value after the new valuation.\n function update(PoolId poolId, ShareClassId scId, AssetId assetId)\n external\n returns (bool isPositive, uint128 diffValue);\n\n /// @notice Updates the valuation method used for this holding.\n function updateValuation(PoolId poolId, ShareClassId scId, AssetId assetId, IERC7726 valuation) external;\n\n /// @notice Sets an account id for an specific kind\n function setAccountId(PoolId poolId, ShareClassId scId, AssetId assetId, uint8 kind, AccountId accountId)\n external;\n\n /// @notice Returns the value of this holding.\n function value(PoolId poolId, ShareClassId scId, AssetId assetId) external view returns (uint128 value);\n\n /// @notice Returns the amount of this holding.\n function amount(PoolId poolId, ShareClassId scId, AssetId assetId) external view returns (uint128 amount);\n\n /// @notice Returns the valuation method used for this holding.\n function valuation(PoolId poolId, ShareClassId scId, AssetId assetId) external view returns (IERC7726);\n\n /// @notice Returns if the holding is a liability\n function isLiability(PoolId poolId, ShareClassId scId, AssetId assetId) external view returns (bool);\n\n /// @notice Returns an account id for an specific kind\n function accountId(PoolId poolId, ShareClassId scId, AssetId assetId, uint8 kind)\n external\n view\n returns (AccountId);\n\n /// @notice Tells if the holding exists for an asset in a share class\n function exists(PoolId poolId, ShareClassId scId, AssetId assetId) external view returns (bool);\n}\n" + }, + "src/hub/interfaces/IHub.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {D18} from \"src/misc/types/D18.sol\";\nimport {IERC7726} from \"src/misc/interfaces/IERC7726.sol\";\n\nimport {VaultUpdateKind} from \"src/common/libraries/MessageLib.sol\";\nimport {IGateway} from \"src/common/interfaces/IGateway.sol\";\nimport {IPoolMessageSender} from \"src/common/interfaces/IGatewaySenders.sol\";\n\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {AccountId} from \"src/common/types/AccountId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {IShareClassManager} from \"src/hub/interfaces/IShareClassManager.sol\";\nimport {IAccounting, JournalEntry} from \"src/hub/interfaces/IAccounting.sol\";\nimport {IHubRegistry} from \"src/hub/interfaces/IHubRegistry.sol\";\nimport {IHoldings} from \"src/hub/interfaces/IHoldings.sol\";\n\n/// @notice Account types used by Hub\nenum AccountType {\n /// @notice Debit normal account for tracking assets\n Asset,\n /// @notice Credit normal account for tracking equities\n Equity,\n /// @notice Credit normal account for tracking losses\n Loss,\n /// @notice Credit normal account for tracking profits\n Gain,\n /// @notice Debit normal account for tracking expenses\n Expense,\n /// @notice Credit normal account for tracking liabilities\n Liability\n}\n\n/// @notice Interface with all methods available in the system used by actors\ninterface IHub {\n event NotifyPool(uint16 indexed centrifugeId, PoolId indexed poolId);\n event NotifyShareClass(uint16 indexed centrifugeId, PoolId indexed poolId, ShareClassId scId);\n event NotifyShareMetadata(\n uint16 indexed centrifugeId, PoolId indexed poolId, ShareClassId scId, string name, string symbol\n );\n event UpdateShareHook(uint16 indexed centrifugeId, PoolId indexed poolId, ShareClassId scId, bytes32 hook);\n event NotifySharePrice(uint16 indexed centrifugeId, PoolId indexed poolId, ShareClassId scId, D18 poolPerShare);\n event NotifyAssetPrice(\n uint16 indexed centrifugeId, PoolId indexed poolId, ShareClassId scId, AssetId assetId, D18 pricePoolPerAsset\n );\n event UpdateRestriction(uint16 indexed centrifugeId, PoolId indexed poolId, ShareClassId scId, bytes payload);\n event UpdateContract(\n uint16 indexed centrifugeId, PoolId indexed poolId, ShareClassId scId, bytes32 target, bytes payload\n );\n\n /// @notice Emitted when a call to `file()` was performed.\n event File(bytes32 what, address addr);\n\n /// @notice Dispatched when the `what` parameter of `file()` is not supported by the implementation.\n error FileUnrecognizedParam();\n\n /// @notice Dispatched when the pool is already unlocked.\n /// It means when calling to `execute()` inside `execute()`.\n error PoolAlreadyUnlocked();\n\n /// @notice Dispatched when the pool can not be unlocked by the caller\n error NotManager();\n\n /// @notice Dispatched when an invalid centrifuge ID is set in the pool ID.\n error InvalidPoolId();\n\n function gateway() external view returns (IGateway);\n function holdings() external view returns (IHoldings);\n function accounting() external view returns (IAccounting);\n function hubRegistry() external view returns (IHubRegistry);\n function sender() external view returns (IPoolMessageSender);\n function shareClassManager() external view returns (IShareClassManager);\n\n /// @notice Updates a contract parameter.\n /// @param what Name of the parameter to update.\n /// Accepts a `bytes32` representation of 'hubRegistry', 'assetRegistry', 'accounting', 'holdings', 'gateway' and '\n /// sender' as string value.\n function file(bytes32 what, address data) external;\n\n /// @notice Notify a deposit for an investor address located in the chain where the asset belongs\n function notifyDeposit(PoolId poolId, ShareClassId scId, AssetId depositAssetId, bytes32 investor, uint32 maxClaims)\n external\n payable;\n\n /// @notice Notify a redemption for an investor address located in the chain where the asset belongs\n function notifyRedeem(PoolId poolId, ShareClassId scId, AssetId payoutAssetId, bytes32 investor, uint32 maxClaims)\n external\n payable;\n\n /// @notice Notify to a CV instance that a new pool is available\n /// @param centrifugeId Chain where CV instance lives\n function notifyPool(PoolId poolId, uint16 centrifugeId) external payable;\n\n /// @notice Notify to a CV instance that a new share class is available\n /// @param centrifugeId Chain where CV instance lives\n /// @param hook The hook address of the share class\n function notifyShareClass(PoolId poolId, ShareClassId scId, uint16 centrifugeId, bytes32 hook) external payable;\n\n /// @notice Notify to a CV instance that share metadata has updated\n function notifyShareMetadata(PoolId poolId, ShareClassId scId, uint16 centrifugeId) external payable;\n\n /// @notice Update on a CV instance the hook of a share token\n function updateShareHook(PoolId poolId, ShareClassId scId, uint16 centrifugeId, bytes32 hook) external payable;\n\n /// @notice Notify to a CV instance the latest available price in POOL_UNIT / SHARE_UNIT\n /// @dev The receiving centrifugeId is derived from the provided assetId\n /// @param centrifugeId Chain to where the share price is notified\n /// @param scId Identifier of the share class\n function notifySharePrice(PoolId poolId, ShareClassId scId, uint16 centrifugeId) external payable;\n\n /// @notice Notify to a CV instance the latest available price in POOL_UNIT / ASSET_UNIT\n /// @dev The receiving centrifugeId is derived from the provided assetId\n /// @param scId Identifier of the share class\n /// @param assetId Identifier of the asset\n function notifyAssetPrice(PoolId poolId, ShareClassId scId, AssetId assetId) external payable;\n\n /// @notice Attach custom data to a pool\n function setPoolMetadata(PoolId poolId, bytes calldata metadata) external payable;\n\n /// @notice Update name & symbol of share class\n function updateShareClassMetadata(PoolId poolId, ShareClassId scId, string calldata name, string calldata symbol)\n external\n payable;\n\n /// @notice Allow/disallow an account to interact as pool manager\n function updateManager(PoolId poolId, address who, bool canManage) external payable;\n\n /// @notice Add a new share class to the pool\n function addShareClass(PoolId poolId, string calldata name, string calldata symbol, bytes32 salt)\n external\n payable\n returns (ShareClassId scId);\n\n /// @notice Approves an asset amount of all deposit requests for the given triplet of pool id, share class id and\n /// deposit asset id.\n /// @param scId Identifier of the share class\n /// @param depositAssetId Identifier of the asset locked for the deposit request\n /// @param nowDepositEpochId The epoch for which deposits will be approved.\n /// @param approvedAssetAmount Ampunt of assets that will be approved\n function approveDeposits(\n PoolId poolId,\n ShareClassId scId,\n AssetId depositAssetId,\n uint32 nowDepositEpochId,\n uint128 approvedAssetAmount\n ) external payable returns (uint128 pendingAssetAmount, uint128 approvedPoolAmount);\n\n /// @notice Approves a percentage of all redemption requests for the given triplet of pool id, share class id and\n /// deposit asset id.\n /// @param scId Identifier of the share class\n /// @param payoutAssetId Identifier of the asset for which all requests want to exchange their share class tokens\n /// @param nowRedeemEpochId The epoch for which redemptions will be approved.\n /// @param approvedShareAmount Amount of shares that will be approved\n function approveRedeems(\n PoolId poolId,\n ShareClassId scId,\n AssetId payoutAssetId,\n uint32 nowRedeemEpochId,\n uint128 approvedShareAmount\n ) external payable returns (uint128 pendingShareAmount);\n\n /// @notice Emits new shares for the given identifier based on the provided NAV per share.\n /// @param depositAssetId Identifier of the deposit asset for which shares should be issued\n /// @param nowIssueEpochId The epoch for which shares will be issued.\n /// @param navPoolPerShare Total value of assets of the share class per share\n function issueShares(\n PoolId poolId,\n ShareClassId id,\n AssetId depositAssetId,\n uint32 nowIssueEpochId,\n D18 navPoolPerShare\n ) external payable returns (uint128 issuedShareAmount, uint128 depositAssetAmount, uint128 depositPoolAmount);\n\n /// @notice Take back shares for the given identifier based on the provided NAV per share.\n /// deposit asset id.\n /// @param payoutAssetId Identifier of the asset for which all requests want to exchange their share class tokens\n /// @param nowRevokeEpochId The epoch for which shares will be issued.\n /// @param navPoolPerShare Total value of assets of the share class per share\n function revokeShares(\n PoolId poolId,\n ShareClassId scId,\n AssetId payoutAssetId,\n uint32 nowRevokeEpochId,\n D18 navPoolPerShare\n ) external payable returns (uint128 revokedShareAmount, uint128 payoutAssetAmount, uint128 payoutPoolAmount);\n\n /// @notice Tells the BalanceSheet to issue/revoke shares.\n function triggerIssueShares(uint16 centrifugeId, PoolId poolId, ShareClassId scId, address who, uint128 shares)\n external\n payable;\n\n /// @notice Tell the BalanceSheet to send a message back with the queued issued/revoked shares.\n function triggerSubmitQueuedShares(uint16 centrifugeId, PoolId poolId, ShareClassId scId) external payable;\n\n /// @notice Tell the BalanceSheet to send a message back with the queued deposits/withdrawals.\n /// @param assetId Identifier of the asset which has queued deposits/withdrawals\n function triggerSubmitQueuedAssets(PoolId poolId, ShareClassId scId, AssetId assetId) external payable;\n\n /// @notice Tell the BalanceSheet to enable or disable the shares queue.\n function setQueue(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bool enabled) external payable;\n\n /// @notice Update remotely a restriction.\n /// @param centrifugeId Chain where CV instance lives.\n /// @param payload content of the restriction update to execute.\n function updateRestriction(PoolId poolId, ShareClassId scId, uint16 centrifugeId, bytes calldata payload)\n external\n payable;\n\n /// @notice Update remotely an existing vault.\n /// @param centrifugeId Chain where CV instance lives.\n /// @param target contract where to execute in CV. Check IUpdateContract interface.\n /// @param payload content of the update to execute.\n function updateContract(\n PoolId poolId,\n ShareClassId scId,\n uint16 centrifugeId,\n bytes32 target,\n bytes calldata payload\n ) external payable;\n\n /// @notice Update the price per share of a share class\n /// @param scId The share class identifier\n /// @param pricePoolPerShare The new price per share\n function updatePricePerShare(PoolId poolId, ShareClassId scId, D18 pricePoolPerShare) external payable;\n\n /// @notice Create a new holding associated to the asset in a share class.\n /// It will register the different accounts used for holdings.\n /// The accounts have to be created beforehand.\n /// The same account can be used for different kinds.\n /// e.g.: The equity, gain, and loss account can be the same account.\n /// They can also be shared across assets.\n /// e.g.: All assets can use the same equity account.\n /// @param valuation Used to transform between payment assets and pool currency\n /// @param assetAccount Used to track the asset value\n /// @param equityAccount Used to track the equity value\n /// @param gainAccount Used to track the gain value\n /// @param lossAccount Used to track the loss value\n function createHolding(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n IERC7726 valuation,\n AccountId assetAccount,\n AccountId equityAccount,\n AccountId gainAccount,\n AccountId lossAccount\n ) external payable;\n\n /// @notice Create a new liablity associated to the asset in a share class.\n /// It will register the different accounts used for holdings.\n /// The accounts have to be created beforehand.\n /// @param valuation Used to transform between the holding asset and pool currency\n /// @param expenseAccount Used to track the expense value\n /// @param liabilityAccount Used to track the liability value\n function createLiability(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n IERC7726 valuation,\n AccountId expenseAccount,\n AccountId liabilityAccount\n ) external payable;\n\n /// @notice Updates the pool currency value of this holding based of the associated valuation.\n function updateHoldingValue(PoolId poolId, ShareClassId scId, AssetId assetId) external payable;\n\n /// @notice Updates the valuation used by a holding\n /// @param valuation Used to transform between the holding asset and pool currency\n function updateHoldingValuation(PoolId poolId, ShareClassId scId, AssetId assetId, IERC7726 valuation)\n external\n payable;\n\n /// @notice Set an account of a holding\n function setHoldingAccountId(PoolId poolId, ShareClassId scId, AssetId assetId, uint8 kind, AccountId accountId)\n external\n payable;\n\n /// @notice Creates an account\n /// @param accountId Then new AccountId used\n /// @param isDebitNormal Determines if the account should be used as debit-normal or credit-normal\n function createAccount(PoolId poolId, AccountId accountId, bool isDebitNormal) external payable;\n\n /// @notice Attach custom data to an account\n function setAccountMetadata(PoolId poolId, AccountId account, bytes calldata metadata) external payable;\n\n /// @notice Perform an accounting entries update.\n function updateJournal(PoolId poolId, JournalEntry[] memory debits, JournalEntry[] memory credits) external;\n}\n" + }, + "src/hub/interfaces/IHubRegistry.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IERC6909Decimals} from \"src/misc/interfaces/IERC6909.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {IShareClassManager} from \"src/hub/interfaces/IShareClassManager.sol\";\n\ninterface IHubRegistry is IERC6909Decimals {\n event NewAsset(AssetId indexed assetId, uint8 decimals);\n event NewPool(PoolId poolId, address indexed manager, AssetId indexed currency);\n event UpdateManager(PoolId indexed poolId, address indexed manager, bool canManage);\n event SetMetadata(PoolId indexed poolId, bytes metadata);\n event UpdateDependency(bytes32 indexed what, address dependency);\n event UpdateCurrency(PoolId indexed poolId, AssetId currency);\n\n error NonExistingPool(PoolId id);\n error AssetAlreadyRegistered();\n error PoolAlreadyRegistered();\n error EmptyAccount();\n error EmptyCurrency();\n error EmptyShareClassManager();\n error AssetNotFound();\n\n /// @notice Register a new asset.\n function registerAsset(AssetId assetId, uint8 decimals_) external;\n\n /// @notice Register a new pool.\n function registerPool(PoolId poolId, address manager, AssetId currency) external;\n\n /// @notice allow/disallow an address as a manager for the pool\n function updateManager(PoolId poolId, address newManager, bool canManage) external;\n\n /// @notice sets metadata for this pool\n function setMetadata(PoolId poolId, bytes calldata metadata) external;\n\n /// @notice updates a dependency of the system\n function updateDependency(bytes32 what, address dependency) external;\n\n /// @notice updates the currency of the pool\n function updateCurrency(PoolId poolId, AssetId currency) external;\n\n /// @notice returns the metadata attached to the pool, if any.\n function metadata(PoolId poolId) external view returns (bytes memory);\n\n /// @notice returns the currency of the pool\n function currency(PoolId poolId) external view returns (AssetId);\n\n /// @notice returns the dependency used in the system\n function dependency(bytes32 what) external view returns (address);\n\n /// @notice returns whether the account is a manager\n function manager(PoolId poolId, address who) external view returns (bool);\n\n /// @notice compute a pool ID given an ID postfix\n function poolId(uint16 centrifugeId, uint48 postfix) external view returns (PoolId poolId);\n\n /// @notice returns the decimals for an asset\n function decimals(AssetId assetId) external view returns (uint8);\n\n /// @notice returns the decimals for a pool\n function decimals(PoolId poolId) external view returns (uint8);\n\n /// @notice checks the existence of a pool\n function exists(PoolId poolId) external view returns (bool);\n\n /// @notice checks the existence of an asset\n function isRegistered(AssetId assetId) external view returns (bool);\n}\n" + }, + "src/hub/interfaces/IShareClassManager.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {D18} from \"src/misc/types/D18.sol\";\nimport {IERC7726} from \"src/misc/interfaces/IERC7726.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nstruct EpochRedeemAmounts {\n /// @dev Amount of shares pending to be redeemed at time of epoch\n uint128 pendingShareAmount;\n /// @dev Total approved amount of redeemed share class tokens\n uint128 approvedShareAmount;\n /// @dev Total asset amount of revoked share class tokens\n uint128 payoutAssetAmount;\n /// @dev The amount of pool currency per unit of asset at time of approval\n D18 pricePoolPerAsset;\n /// @dev The amount of pool currency per unit of share at time of revocation\n D18 navPoolPerShare;\n /// @dev block timestamp when shares of epoch were revoked\n uint64 revokedAt;\n}\n\nstruct EpochInvestAmounts {\n /// @dev Total pending asset amount of deposit asset at time of epoch\n uint128 pendingAssetAmount;\n /// @dev Total approved asset amount of deposit asset\n uint128 approvedAssetAmount;\n /// @dev Total approved pool amount of deposit asset\n uint128 approvedPoolAmount;\n /// @dev The amount of pool currency per unit of asset at time of approval\n D18 pricePoolPerAsset;\n /// @dev The amount of pool currency per unit of share at time of issuance\n D18 navPoolPerShare;\n /// @dev block timestamp when shares of epoch were issued\n uint64 issuedAt;\n}\n\nstruct UserOrder {\n /// @dev Pending amount in deposit asset denomination\n uint128 pending;\n /// @dev Index of epoch in which last order was made\n uint32 lastUpdate;\n}\n\nstruct ShareClassMetadata {\n /// @dev The name of the share class token\n string name;\n /// @dev The symbol of the share class token\n string symbol;\n /// @dev The salt of the share class token\n bytes32 salt;\n}\n\nstruct ShareClassMetrics {\n /// @dev Total number of shares\n uint128 totalIssuance;\n /// @dev The latest net asset value per share class token\n D18 navPerShare;\n}\n\nstruct QueuedOrder {\n /// @dev Whether the user requested a cancellation which is now queued\n bool isCancelling;\n /// @dev The queued increased request amount\n uint128 amount;\n}\n\nenum RequestType {\n /// @dev Whether the request is a deposit one\n Deposit,\n /// @dev Whether the request is a redeem one\n Redeem\n}\n\nstruct EpochId {\n uint32 deposit;\n uint32 redeem;\n uint32 issue;\n uint32 revoke;\n}\n\ninterface IShareClassManager {\n /// Events\n event AddShareClass(\n PoolId indexed poolId, ShareClassId indexed scId, uint32 indexed index, string name, string symbol, bytes32 salt\n );\n event UpdateMetadata(PoolId indexed poolId, ShareClassId indexed scId, string name, string symbol);\n event ApproveDeposits(\n PoolId indexed poolId,\n ShareClassId indexed scId,\n AssetId indexed depositAssetId,\n uint32 epoch,\n uint128 approvedPoolAmount,\n uint128 approvedAssetAmount,\n uint128 pendingAssetAmount\n );\n event ApproveRedeems(\n PoolId indexed poolId,\n ShareClassId indexed scId,\n AssetId indexed payoutAssetId,\n uint32 epoch,\n uint128 approvedShareAmount,\n uint128 pendingShareAmount\n );\n event IssueShares(\n PoolId indexed poolId,\n ShareClassId indexed scId,\n AssetId indexed depositAssetId,\n uint32 epoch,\n D18 navPoolPerShare,\n D18 navAssetPerShare,\n uint128 issuedShareAmount\n );\n event RemoteIssueShares(PoolId indexed poolId, ShareClassId indexed scId, uint128 issuedShareAmount);\n event RevokeShares(\n PoolId indexed poolId,\n ShareClassId indexed scId,\n AssetId indexed payoutAssetId,\n uint32 epoch,\n D18 navPoolPerShare,\n D18 navAssetPerShare,\n uint128 revokedShareAmount,\n uint128 revokedAssetAmount,\n uint128 revokedPoolAmount\n );\n event RemoteRevokeShares(PoolId indexed poolId, ShareClassId indexed scId, uint128 revokedAssetAmount);\n event ClaimDeposit(\n PoolId indexed poolId,\n ShareClassId indexed scId,\n uint32 epoch,\n bytes32 investor,\n AssetId indexed depositAssetId,\n uint128 paymentAssetAmount,\n uint128 pendingAssetAmount,\n uint128 claimedShareAmount,\n uint64 issuedAt\n );\n event ClaimRedeem(\n PoolId indexed poolId,\n ShareClassId indexed scId,\n uint32 epoch,\n bytes32 investor,\n AssetId indexed payoutAssetId,\n uint128 paymentShareAmount,\n uint128 pendingShareAmount,\n uint128 claimedAssetAmount,\n uint64 revokedAt\n );\n event AddShareClass(PoolId indexed poolId, ShareClassId indexed scId, uint32 indexed index);\n event UpdateShareClass(PoolId indexed poolId, ShareClassId indexed scId, D18 navPoolPerShare);\n event UpdateDepositRequest(\n PoolId indexed poolId,\n ShareClassId indexed scId,\n AssetId indexed depositAssetId,\n uint32 epoch,\n bytes32 investor,\n uint128 pendingUserAssetAmount,\n uint128 pendingTotalAssetAmount,\n uint128 queuedUserAssetAmount,\n bool pendingCancellation\n );\n event UpdateRedeemRequest(\n PoolId indexed poolId,\n ShareClassId indexed scId,\n AssetId indexed payoutAssetId,\n uint32 epoch,\n bytes32 investor,\n uint128 pendingUserShareAmount,\n uint128 pendingTotalShareAmount,\n uint128 queuedUserShareAmount,\n bool pendingCancellation\n );\n\n /// Errors\n error EpochNotInSequence(uint32 providedEpoch, uint32 nowEpoch);\n error NoOrderFound();\n error InsufficientPending();\n error ApprovalRequired();\n error IssuanceRequired();\n error AlreadyIssued();\n error RevocationRequired();\n error ZeroApprovalAmount();\n error InvalidMetadataSize();\n error InvalidMetadataName();\n error InvalidMetadataSymbol();\n error InvalidSalt();\n error AlreadyUsedSalt();\n error RevokeMoreThanIssued();\n error PoolMissing();\n error ShareClassNotFound();\n error EpochNotFound();\n error DecreaseMoreThanIssued();\n error CancellationQueued();\n\n /// Functions\n\n /// @notice Creates or updates a request to deposit (exchange) an asset amount for share class tokens.\n ///\n /// @param poolId Identifier of the pool\n /// @param scId Identifier of the share class\n /// @param amount Asset token amount which is deposited\n /// @param investor Centrifuge Vault address of the entity which is depositing\n /// @param depositAssetId Identifier of the asset which the investor used for their deposit request\n function requestDeposit(PoolId poolId, ShareClassId scId, uint128 amount, bytes32 investor, AssetId depositAssetId)\n external;\n\n /// @notice Cancels a pending deposit request.\n ///\n /// @param poolId Identifier of the pool\n /// @param scId Identifier of the share class\n /// @param investor Centrifuge Vault address of the entity which is cancelling\n /// @param depositAssetId Identifier of the asset which the investor used for their deposit request\n /// @return cancelledAssetAmount The deposit amount which was previously pending and is now cancelled. This amount\n /// was not potentially (partially) swapped to the pool amount in case the deposit asset cannot be exchanged 1:1\n /// into the pool token\n function cancelDepositRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId depositAssetId)\n external\n returns (uint128 cancelledAssetAmount);\n\n /// @notice Creates or updates a request to redeem (exchange) share class tokens for some asset.\n ///\n /// @param poolId Identifier of the pool\n /// @param scId Identifier of the share class\n /// @param amount Share class token amount which should be redeemed\n /// @param investor Centrifuge Vault address of the entity which is redeeming\n /// @param payoutAssetId Identifier of the asset which the investor eventually receives back for their redeemed\n /// share class tokens\n function requestRedeem(PoolId poolId, ShareClassId scId, uint128 amount, bytes32 investor, AssetId payoutAssetId)\n external;\n\n /// @notice Cancels a pending redeem request.\n ///\n /// @param poolId Identifier of the pool\n /// @param scId Identifier of the share class\n /// @param investor Centrifuge Vault address of the entity which is cancelling\n /// @param payoutAssetId Identifier of the asset which the investor eventually receives back for their redeemed\n /// share class tokens\n /// @return cancelledShareAmount The redeem amount which was previously pending and is now cancelled\n function cancelRedeemRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId payoutAssetId)\n external\n returns (uint128 cancelledShareAmount);\n\n /// @notice Approves an asset amount of all deposit requests for the given triplet of pool id, share class id and\n /// deposit asset id.\n /// @dev nowDepositEpochId MUST be called sequentially.\n ///\n /// @param poolId Identifier of the pool\n /// @param scId Identifier of the share class\n /// @param depositAssetId Identifier of the asset locked for the deposit request\n /// @param nowDepositEpochId The epoch for which shares will be approved.\n /// @param approvedAssetAmount Amount of assets that will be approved for deposit\n /// @param pricePoolPerAsset Amount of pool unit one gets for a unit of asset\n /// @return pendingAssetAmount Amount of assets still pending for deposit\n /// @return approvedPoolAmount Amount of pool units approved for deposit\n function approveDeposits(\n PoolId poolId,\n ShareClassId scId,\n AssetId depositAssetId,\n uint32 nowDepositEpochId,\n uint128 approvedAssetAmount,\n D18 pricePoolPerAsset\n ) external returns (uint128 pendingAssetAmount, uint128 approvedPoolAmount);\n\n /// @notice Approves a share class token amount of all redeem requests for the given triplet of pool id, share class\n /// id and payout asset id.\n /// @dev nowRedeemEpochId MUST be called sequentially.\n ///\n /// @param poolId Identifier of the pool\n /// @param scId Identifier of the share class\n /// @param payoutAssetId Identifier of the asset for which all requests want to exchange their share class tokens\n /// for\n /// @param nowRedeemEpochId The epoch for which shares will be approved.\n /// @param approvedShareAmount Amount of shares that will be approved for redemption\n /// @param pricePoolPerAsset Amount of pool unit one gets for a unit of asset\n /// @return pendingShareAmount Sum of redemption request amounts in share class token amount which was not approved\n function approveRedeems(\n PoolId poolId,\n ShareClassId scId,\n AssetId payoutAssetId,\n uint32 nowRedeemEpochId,\n uint128 approvedShareAmount,\n D18 pricePoolPerAsset\n ) external returns (uint128 pendingShareAmount);\n\n /// @notice Emits new shares for the given identifier based on the provided NAV per share.\n /// @dev nowIssueEpochId MUST be called sequentially.\n ///\n /// @param poolId Identifier of the pool\n /// @param scId Identifier of the share class\n /// @param depositAssetId Identifier of the deposit asset for which shares should be issued\n /// @param nowIssueEpochId The epoch for which shares will be issued.\n /// @param navPoolPerShare The nav per share value of the share class (in the pool currency denomination. Conversion\n /// to asset price is done onchain based on the valuation of the asset at approval)\n /// @return issuedShareAmount Amount of shares that have been issued\n function issueShares(\n PoolId poolId,\n ShareClassId scId,\n AssetId depositAssetId,\n uint32 nowIssueEpochId,\n D18 navPoolPerShare\n ) external returns (uint128 issuedShareAmount, uint128 depositAssetAmount, uint128 depositPoolAmount);\n\n /// @notice Take back shares for the given identifier based on the provided NAV per share.\n /// @dev nowRevokeEpochId MUST be called sequentially.\n ///\n /// @param poolId Identifier of the pool\n /// @param scId Identifier of the share class\n /// @param payoutAssetId Identifier of the payout asset\n /// @param nowRevokeEpochId The epoch for which shares will be revoked.\n /// @param navPoolPerShare The nav per share value of the share class (in the pool currency denomination. Conversion\n /// to asset price is done onchain based on the valuation of the asset at approval)\n /// @return revokedShareAmount Amount of shares that have been revoked\n /// @return payoutAssetAmount Converted amount of payout asset based on number of revoked shares\n /// @return payoutPoolAmount Converted amount of pool currency based on number of revoked shares\n function revokeShares(\n PoolId poolId,\n ShareClassId scId,\n AssetId payoutAssetId,\n uint32 nowRevokeEpochId,\n D18 navPoolPerShare\n ) external returns (uint128 revokedShareAmount, uint128 payoutAssetAmount, uint128 payoutPoolAmount);\n\n /// @notice Collects shares for an investor after their deposit request was (partially) approved and new shares were\n /// issued.\n ///\n /// @param poolId Identifier of the pool\n /// @param scId Identifier of the share class\n /// @param investor Centrifuge Vault address of the recipient of the claimed share class tokens\n /// @param depositAssetId Identifier of the asset which the investor used for their deposit request\n /// @return payoutShareAmount Amount of shares which the investor receives\n /// @return paymentAssetAmount Amount of deposit asset which was taken as payment\n /// @return cancelledAssetAmount Amount of deposit asset which was cancelled due to being queued\n /// @return canClaimAgain Whether another call to claimRedeem is needed until investor has fully claimed investments\n function claimDeposit(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId depositAssetId)\n external\n returns (\n uint128 payoutShareAmount,\n uint128 paymentAssetAmount,\n uint128 cancelledAssetAmount,\n bool canClaimAgain\n );\n\n /// @notice Collects an asset amount for an investor after their redeem request was (partially) approved and shares\n /// were revoked.\n ///\n /// @param poolId Identifier of the pool\n /// @param scId Identifier of the share class\n /// @param investor Centrifuge Vault address of the recipient of the claimed asset amount\n /// @param payoutAssetId Identifier of the asset which the investor requested to receive back for their redeemed\n /// shares\n /// @return payoutAssetAmount Amount of payout amount which the investor receives\n /// @return paymentShareAmount Amount of shares which the investor redeemed\n /// @return cancelledShareAmount Amount of shares which were cancelled due to being queued\n /// @return canClaimAgain Whether another call to claimRedeem is needed until investor has fully claimed redemptions\n function claimRedeem(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId payoutAssetId)\n external\n returns (\n uint128 payoutAssetAmount,\n uint128 paymentShareAmount,\n uint128 cancelledShareAmount,\n bool canClaimAgain\n );\n\n /// @notice Increases the share class issuance\n ///\n /// @param poolId Identifier of the pool\n /// @param scId Identifier of the share class\n /// @param amount The amount to increase the share class issuance by\n function increaseShareClassIssuance(PoolId poolId, ShareClassId scId, uint128 amount) external;\n\n /// @notice Decreases the share class issuance\n ///\n /// @param poolId Identifier of the pool\n /// @param scId Identifier of the share class\n /// @param amount The amount to decrease the share class issuance by\n function decreaseShareClassIssuance(PoolId poolId, ShareClassId scId, uint128 amount) external;\n\n /// @notice Adds a new share class to the given pool.\n ///\n /// @param poolId Identifier of the pool\n /// @param name The name of the share class\n /// @param symbol The symbol of the share class\n /// @param salt The salt used for deploying the share class tokens\n /// @return scId Identifier of the newly added share class\n function addShareClass(PoolId poolId, string calldata name, string calldata symbol, bytes32 salt)\n external\n returns (ShareClassId scId);\n\n /// @notice Updates the price pool unit per share unit of a share class\n ///\n /// @param poolId Identifier of the pool\n /// @param scId Identifier of the share class\n /// @param pricePoolPerShare The price per share of the share class (in the pool currency denomination)\n function updatePricePerShare(PoolId poolId, ShareClassId scId, D18 pricePoolPerShare) external;\n\n /// @notice Updates the metadata of a share class.\n ///\n /// @param poolId Identifier of the pool\n /// @param scId Identifier of the share class\n /// @param name The name of the share class\n /// @param symbol The symbol of the share class\n function updateMetadata(PoolId poolId, ShareClassId scId, string calldata name, string calldata symbol) external;\n\n /// @notice Returns the number of share classes for the given pool\n ///\n /// @param poolId Identifier of the pool in question\n /// @return count Number of share classes for the given pool\n function shareClassCount(PoolId poolId) external view returns (uint32 count);\n\n /// @notice Checks the existence of a share class.\n ///\n /// @param poolId Identifier of the pool\n /// @param scId Identifier of the share class\n function exists(PoolId poolId, ShareClassId scId) external view returns (bool);\n\n /// @notice Returns the current ongoing epoch id for deposits\n ///\n /// @param scId Identifier of the share class\n /// @param depositAssetId AssetId of the payment asset\n function nowDepositEpoch(ShareClassId scId, AssetId depositAssetId) external view returns (uint32);\n\n /// @notice Returns the epoch for which will be issued next\n ///\n /// @param scId Identifier of the share class\n /// @param depositAssetId AssetId of the payment asset\n function nowIssueEpoch(ShareClassId scId, AssetId depositAssetId) external view returns (uint32);\n\n /// @notice Returns the current ongoing epoch id for deposits\n ///\n /// @param scId Identifier of the share class\n /// @param payoutAssetId AssetId of the payment asset\n function nowRedeemEpoch(ShareClassId scId, AssetId payoutAssetId) external view returns (uint32);\n\n /// @notice Returns the epoch for which will be revoked next\n ///\n /// @param scId Identifier of the share class\n /// @param depositAssetId AssetId of the payment asset\n function nowRevokeEpoch(ShareClassId scId, AssetId depositAssetId) external view returns (uint32);\n\n /// @notice Returns an upper bound for possible calls to `function claimDeposit(..)`\n ///\n /// @param scId Identifier of the share class\n /// @param investor Recipient of the share class tokens\n /// @param depositAssetId AssetId of the payment asset\n function maxDepositClaims(ShareClassId scId, bytes32 investor, AssetId depositAssetId)\n external\n view\n returns (uint32 maxClaims);\n\n /// @notice Returns an upper bound for possible calls to `function claimRedeem(..)`\n ///\n /// @param scId Identifier of the share class\n /// @param investor Recipient of the payout assets\n /// @param payoutAssetId AssetId of the payout asset\n function maxRedeemClaims(ShareClassId scId, bytes32 investor, AssetId payoutAssetId)\n external\n view\n returns (uint32 maxClaims);\n\n /// @notice Exposes relevant metrics for a share class\n ///\n /// @return totalIssuance The total number of shares known to the CP side\n /// @return pricePoolPerShare The amount of pool units per unit share\n function metrics(ShareClassId scId) external view returns (uint128 totalIssuance, D18 pricePoolPerShare);\n\n /// @notice Determines the next share class id for the given pool.\n ///\n /// @param poolId Identifier of the pool\n /// @return scId Identifier of the next share class\n function previewNextShareClassId(PoolId poolId) external view returns (ShareClassId scId);\n\n /// @notice Determines the share class id for the given pool and index.\n ///\n /// @param poolId Identifier of the pool\n /// @param index The pool-internal index of the share class id\n /// @return scId Identifier of the underlying share class\n function previewShareClassId(PoolId poolId, uint32 index) external pure returns (ShareClassId scId);\n\n /// @notice returns The metadata of the share class.\n ///\n /// @param scId Identifier of the share class\n /// @return name The registered name of the share class token\n /// @return symbol The registered symbol of the share class token\n /// @return salt The registered salt of the share class token, used for deterministic deployments\n function metadata(ShareClassId scId) external returns (string memory name, string memory symbol, bytes32 salt);\n}\n" + }, + "src/misc/Auth.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IAuth} from \"src/misc/interfaces/IAuth.sol\";\n\n/// @title Auth\n/// @notice Simple authentication pattern\n/// @author Based on code from https://github.com/makerdao/dss\nabstract contract Auth is IAuth {\n /// @inheritdoc IAuth\n mapping(address => uint256) public wards;\n\n constructor(address initialWard) {\n wards[initialWard] = 1;\n emit Rely(initialWard);\n }\n\n /// @dev Check if the msg.sender has permissions\n modifier auth() {\n require(wards[msg.sender] == 1, NotAuthorized());\n _;\n }\n\n /// @inheritdoc IAuth\n function rely(address user) public auth {\n wards[user] = 1;\n emit Rely(user);\n }\n\n /// @inheritdoc IAuth\n function deny(address user) public auth {\n wards[user] = 0;\n emit Deny(user);\n }\n}\n" + }, + "src/misc/BaseValuation.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IBaseValuation} from \"src/misc/interfaces/IBaseValuation.sol\";\nimport {IERC6909Decimals} from \"src/misc/interfaces/IERC6909.sol\";\n\nimport {Auth} from \"src/misc/Auth.sol\";\n\nabstract contract BaseValuation is Auth, IBaseValuation {\n /// @notice ERC6909 dependency.\n IERC6909Decimals public erc6909;\n\n constructor(IERC6909Decimals erc6909_, address deployer) Auth(deployer) {\n erc6909 = erc6909_;\n }\n\n /// @inheritdoc IBaseValuation\n function file(bytes32 what, address data) external auth {\n if (what == \"erc6909\") erc6909 = IERC6909Decimals(data);\n else revert FileUnrecognizedParam();\n\n emit File(what, data);\n }\n\n /// @notice Obtain the correct decimals given an asset address\n function _getDecimals(address asset) internal view returns (uint8) {\n return erc6909.decimals(uint160(asset));\n }\n}\n" + }, + "src/misc/ERC20.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {EIP712Lib} from \"src/misc/libraries/EIP712Lib.sol\";\nimport {SignatureLib} from \"src/misc/libraries/SignatureLib.sol\";\n\nimport {IERC20, IERC20Metadata, IERC20Permit} from \"src/misc/interfaces/IERC20.sol\";\n\n/// @title ERC20\n/// @notice Standard ERC-20 implementation, with mint/burn functionality and permit logic.\n/// @author Modified from https://github.com/makerdao/xdomain-dss/blob/master/src/Dai.sol\ncontract ERC20 is Auth, IERC20Metadata, IERC20Permit {\n error FileUnrecognizedParam();\n\n /// @inheritdoc IERC20Metadata\n string public name;\n /// @inheritdoc IERC20Metadata\n string public symbol;\n /// @inheritdoc IERC20Metadata\n uint8 public immutable decimals;\n /// @inheritdoc IERC20\n uint256 public totalSupply;\n\n mapping(address => uint256) private balances;\n\n /// @inheritdoc IERC20\n mapping(address => mapping(address => uint256)) public allowance;\n /// @inheritdoc IERC20Permit\n mapping(address => uint256) public nonces;\n\n // --- EIP712 ---\n bytes32 private immutable nameHash;\n bytes32 private immutable versionHash;\n uint256 public immutable deploymentChainId;\n bytes32 private immutable _DOMAIN_SEPARATOR;\n bytes32 public constant PERMIT_TYPEHASH =\n keccak256(\"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\");\n\n // --- Events ---\n event File(bytes32 indexed what, string data);\n\n constructor(uint8 decimals_) Auth(msg.sender) {\n decimals = decimals_;\n\n nameHash = keccak256(bytes(\"Centrifuge\"));\n versionHash = keccak256(bytes(\"1\"));\n deploymentChainId = block.chainid;\n _DOMAIN_SEPARATOR = EIP712Lib.calculateDomainSeparator(nameHash, versionHash);\n }\n\n function _balanceOf(address user) internal view virtual returns (uint256) {\n return balances[user];\n }\n\n /// @inheritdoc IERC20\n function balanceOf(address user) public view virtual returns (uint256) {\n return _balanceOf(user);\n }\n\n function _setBalance(address user, uint256 value) internal virtual {\n balances[user] = value;\n }\n\n /// @inheritdoc IERC20Permit\n function DOMAIN_SEPARATOR() public view returns (bytes32) {\n return block.chainid == deploymentChainId\n ? _DOMAIN_SEPARATOR\n : EIP712Lib.calculateDomainSeparator(nameHash, versionHash);\n }\n\n // --- Administration ---\n function file(bytes32 what, string memory data) public virtual auth {\n if (what == \"name\") name = data;\n else if (what == \"symbol\") symbol = data;\n else revert FileUnrecognizedParam();\n emit File(what, data);\n }\n\n // --- ERC20 Mutations ---\n /// @inheritdoc IERC20\n function transfer(address to, uint256 value) public virtual returns (bool) {\n require(to != address(0) && to != address(this), InvalidAddress());\n uint256 balance = balanceOf(msg.sender);\n require(balance >= value, InsufficientBalance());\n\n unchecked {\n _setBalance(msg.sender, balance - value);\n // note: we don't need an overflow check here b/c sum of all balances == totalSupply\n _setBalance(to, _balanceOf(to) + value);\n }\n\n emit Transfer(msg.sender, to, value);\n\n return true;\n }\n\n /// @inheritdoc IERC20\n function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {\n return _transferFrom(msg.sender, from, to, value);\n }\n\n function _transferFrom(address sender, address from, address to, uint256 value) internal virtual returns (bool) {\n require(to != address(0) && to != address(this), InvalidAddress());\n uint256 balance = balanceOf(from);\n require(balance >= value, InsufficientBalance());\n\n if (from != sender) {\n uint256 allowed = allowance[from][sender];\n if (allowed != type(uint256).max) {\n require(allowed >= value, InsufficientAllowance());\n unchecked {\n allowance[from][sender] = allowed - value;\n }\n }\n }\n\n unchecked {\n _setBalance(from, balance - value);\n // note: we don't need an overflow check here b/c sum of all balances == totalSupply\n _setBalance(to, _balanceOf(to) + value);\n }\n\n emit Transfer(from, to, value);\n\n return true;\n }\n\n /// @inheritdoc IERC20\n function approve(address spender, uint256 value) external returns (bool) {\n allowance[msg.sender][spender] = value;\n\n emit Approval(msg.sender, spender, value);\n\n return true;\n }\n\n // --- Mint/Burn ---\n function mint(address to, uint256 value) public virtual auth {\n require(to != address(0) && to != address(this), InvalidAddress());\n unchecked {\n // We don't need an overflow check here b/c balances[to] <= totalSupply\n // and there is an overflow check below\n _setBalance(to, _balanceOf(to) + value);\n }\n totalSupply += value;\n\n emit Transfer(address(0), to, value);\n }\n\n function burn(address from, uint256 value) public virtual auth {\n uint256 balance = balanceOf(from);\n require(balance >= value, InsufficientBalance());\n\n if (from != msg.sender) {\n uint256 allowed = allowance[from][msg.sender];\n if (allowed != type(uint256).max) {\n require(allowed >= value, InsufficientAllowance());\n\n unchecked {\n allowance[from][msg.sender] = allowed - value;\n }\n }\n }\n\n unchecked {\n // We don't need overflow checks b/c require(balance >= value) and balance <= totalSupply\n _setBalance(from, balance - value);\n totalSupply -= value;\n }\n\n emit Transfer(from, address(0), value);\n }\n\n // --- Approve by signature ---\n function permit(address owner, address spender, uint256 value, uint256 deadline, bytes memory signature) public {\n require(block.timestamp <= deadline, PermitExpired());\n\n uint256 nonce;\n unchecked {\n nonce = nonces[owner]++;\n }\n\n bytes32 digest = keccak256(\n abi.encodePacked(\n \"\\x19\\x01\",\n DOMAIN_SEPARATOR(),\n keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonce, deadline))\n )\n );\n\n require(SignatureLib.isValidSignature(owner, digest, signature), InvalidPermit());\n\n allowance[owner][spender] = value;\n emit Approval(owner, spender, value);\n }\n\n /// @inheritdoc IERC20Permit\n function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)\n external\n {\n permit(owner, spender, value, deadline, abi.encodePacked(r, s, v));\n }\n}\n" + }, + "src/misc/IdentityValuation.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {d18} from \"src/misc/types/D18.sol\";\nimport {IERC7726} from \"src/misc/interfaces/IERC7726.sol\";\nimport {IIdentityValuation} from \"src/misc/interfaces/IIdentityValuation.sol\";\nimport {IERC6909Decimals} from \"src/misc/interfaces/IERC6909.sol\";\nimport {BaseValuation} from \"src/misc/BaseValuation.sol\";\n\nimport {PricingLib} from \"src/common/libraries/PricingLib.sol\";\n\ncontract IdentityValuation is BaseValuation, IIdentityValuation {\n constructor(IERC6909Decimals erc6909, address deployer) BaseValuation(erc6909, deployer) {}\n\n /// @inheritdoc IERC7726\n function getQuote(uint256 baseAmount, address base, address quote) external view returns (uint256 quoteAmount) {\n return PricingLib.convertWithPrice(baseAmount, _getDecimals(base), _getDecimals(quote), d18(1e18));\n }\n}\n" + }, + "src/misc/Multicall.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.28;\n\n// NOTE: This file has warning disabled due https://github.com/ethereum/solidity/issues/14359\n// If perform any change on it, please ensure no other warnings appears\n\nimport {IMulticall} from \"src/misc/interfaces/IMulticall.sol\";\nimport {ReentrancyProtection} from \"src/misc/ReentrancyProtection.sol\";\n\nabstract contract Multicall is ReentrancyProtection, IMulticall {\n function multicall(bytes[] calldata data) public payable virtual protected {\n uint256 totalBytes = data.length;\n for (uint256 i; i < totalBytes; ++i) {\n (bool success, bytes memory returnData) = address(this).delegatecall(data[i]);\n if (!success) {\n uint256 length = returnData.length;\n require(length != 0, CallFailedWithEmptyRevert());\n\n assembly (\"memory-safe\") {\n revert(add(32, returnData), length)\n }\n }\n }\n }\n}\n" + }, + "src/misc/Recoverable.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {IERC6909} from \"src/misc/interfaces/IERC6909.sol\";\nimport {SafeTransferLib} from \"src/misc/libraries/SafeTransferLib.sol\";\n\nimport {IRecoverable, ETH_ADDRESS} from \"src/misc/interfaces/IRecoverable.sol\";\n\nabstract contract Recoverable is Auth, IRecoverable {\n /// @inheritdoc IRecoverable\n function recoverTokens(address token, address receiver, uint256 amount) public auth {\n if (token == ETH_ADDRESS) {\n SafeTransferLib.safeTransferETH(receiver, amount);\n } else {\n SafeTransferLib.safeTransfer(token, receiver, amount);\n }\n }\n\n /// @inheritdoc IRecoverable\n function recoverTokens(address token, uint256 tokenId, address receiver, uint256 amount) external auth {\n if (tokenId == 0) {\n recoverTokens(token, receiver, amount);\n } else {\n IERC6909(token).transfer(receiver, tokenId, amount);\n }\n }\n}\n" + }, + "src/misc/ReentrancyProtection.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.28;\n\n// NOTE: This file has warning disabled due https://github.com/ethereum/solidity/issues/14359\n// If perform any change on it, please ensure no other warnings appears\n\nabstract contract ReentrancyProtection {\n /// @notice Dispatched when there is a re-entrancy issue\n error UnauthorizedSender();\n\n address private transient _initiator;\n\n /// @dev The method is protected for reentrancy issues.\n modifier protected() {\n if (_initiator == address(0)) {\n // Single call re-entrancy lock\n _initiator = msg.sender;\n _;\n _initiator = address(0);\n } else {\n // Multicall re-entrancy lock\n require(msg.sender == _initiator, UnauthorizedSender());\n _;\n }\n }\n}\n" + }, + "src/misc/interfaces/IAuth.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\ninterface IAuth {\n event Rely(address indexed user);\n event Deny(address indexed user);\n\n error NotAuthorized();\n\n /// @notice Returns whether the target is a ward (has admin access)\n function wards(address target) external view returns (uint256);\n\n /// @notice Make user a ward (give them admin access)\n function rely(address user) external;\n\n /// @notice Remove user as a ward (remove admin access)\n function deny(address user) external;\n}\n" + }, + "src/misc/interfaces/IBaseValuation.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IERC7726} from \"src/misc/interfaces/IERC7726.sol\";\n\n/// Provides a base implementation for all ERC7726 valuation in the system\ninterface IBaseValuation is IERC7726 {\n /// @notice Emitted when a call to `file()` was performed.\n event File(bytes32 indexed what, address addr);\n\n /// @notice Dispatched when the `what` parameter of `file()` is not supported by the implementation.\n error FileUnrecognizedParam();\n\n /// @notice Updates a contract parameter.\n /// @param what Name of the parameter to update.\n /// Accepts a `bytes32` representation of 'assetRegistry' string value.\n /// @param data New value given to the `what` parameter\n function file(bytes32 what, address data) external;\n}\n" + }, + "src/misc/interfaces/IERC20.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\n/// @title IERC20\n/// @dev Interface of the ERC20 standard as defined in the EIP.\n/// @author Modified from OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)\ninterface IERC20 {\n error InvalidAddress();\n error InsufficientBalance();\n error InsufficientAllowance();\n\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n error PermitExpired();\n error InvalidPermit();\n\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)\n external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\ninterface IERC20Wrapper {\n /**\n * @dev Returns the address of the underlying ERC-20 token that is being wrapped.\n */\n function underlying() external view returns (address);\n\n /**\n * @dev Allow a user to deposit underlying tokens and mint the corresponding number of wrapped tokens.\n */\n function depositFor(address account, uint256 value) external returns (bool);\n\n /**\n * @dev Allow a user to burn a number of wrapped tokens and withdraw the corresponding number of underlying tokens.\n */\n function withdrawTo(address account, uint256 value) external returns (bool);\n}\n" + }, + "src/misc/interfaces/IERC6909.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IERC165} from \"forge-std/interfaces/IERC165.sol\";\n\ninterface IERC6909 is IERC165 {\n error EmptyOwner();\n error EmptyAmount();\n error InvalidTokenId();\n error InsufficientBalance(address owner, uint256 tokenId);\n error InsufficientAllowance(address sender, uint256 tokenId);\n\n event OperatorSet(address indexed owner, address indexed operator, bool approved);\n event Approval(address indexed owner, address indexed spender, uint256 indexed tokenId, uint256 amount);\n event Transfer(address caller, address indexed from, address indexed to, uint256 indexed tokenId, uint256 amount);\n\n /// @notice Owner balance of a tokenId.\n /// @param owner The address of the owner.\n /// @param tokenId The id of the token.\n /// @return amount The balance of the token.\n function balanceOf(address owner, uint256 tokenId) external view returns (uint256 amount);\n\n /// @notice Spender allowance of a tokenId.\n /// @param owner The address of the owner.\n /// @param spender The address of the spender.\n /// @param tokenId The id of the token.\n /// @return amount The allowance of the token.\n function allowance(address owner, address spender, uint256 tokenId) external view returns (uint256 amount);\n\n /// @notice Checks if a spender is approved by an owner as an operator.\n /// @param owner The address of the owner.\n /// @param spender The address of the spender.\n /// @return approved The approval status.\n function isOperator(address owner, address spender) external view returns (bool approved);\n\n /// @notice Transfers an amount of a tokenId from the caller to a receiver.\n /// @param receiver The address of the receiver.\n /// @param tokenId The id of the token.\n /// @param amount The amount of the token.\n /// @return bool True, always, unless the function reverts.\n function transfer(address receiver, uint256 tokenId, uint256 amount) external returns (bool);\n\n /// @notice Transfers an amount of a tokenId from a sender to a receiver.\n /// @param sender The address of the sender.\n /// @param receiver The address of the receiver.\n /// @param tokenId The id of the token.\n /// @param amount The amount of the token.\n /// @return bool True, always, unless the function reverts.\n function transferFrom(address sender, address receiver, uint256 tokenId, uint256 amount) external returns (bool);\n\n /// @notice Approves an amount of a tokenId to a spender.\n /// @param spender The address of the spender.\n /// @param tokenId The id of the token.\n /// @param amount The amount of the token.\n /// @return bool True, always.\n function approve(address spender, uint256 tokenId, uint256 amount) external returns (bool);\n\n /// @notice Sets or removes an operator for the caller.\n /// @param operator The address of the operator.\n /// @param approved The approval status.\n /// @return bool True, always.\n function setOperator(address operator, bool approved) external returns (bool);\n}\n\ninterface IERC6909URIExt {\n event TokenURISet(uint256 indexed tokenId, string uri);\n event ContractURISet(address indexed target, string uri);\n\n error EmptyURI();\n\n /// @return uri Returns the common token URI.\n function contractURI() external view returns (string memory);\n\n /// @dev Returns empty string if tokenId does not exist.\n /// MAY implemented to throw MissingURI(tokenId) error.\n /// @param tokenId The token to query URI for.\n /// @return uri A string representing the uri for the specific tokenId.\n function tokenURI(uint256 tokenId) external view returns (string memory);\n}\n\ninterface IERC6909NFT is IERC6909, IERC6909URIExt {\n error UnknownTokenId(address owner, uint256 tokenId);\n error LessThanMinimalDecimal(uint8 minimal, uint8 actual);\n\n /// @notice Provide URI for a specific tokenId.\n /// @param tokenId Token Id.\n /// @param URI URI to a document defining the collection as a whole.\n function setTokenURI(uint256 tokenId, string memory URI) external;\n\n /// @dev Optional method to set up the contract URI if needed.\n /// @param URI URI to a document defining the collection as a whole.\n function setContractURI(string memory URI) external;\n\n /// @notice Mint new tokens for a given owner and sets tokenURI.\n /// @dev For non-fungible tokens, call with amount = 1, for fungible it could be any amount.\n /// TokenId is auto incremented by one.\n ///\n /// @param owner Creates supply of a given tokenId by amount for owner.\n /// @param tokenURI URI fortestBurningToken the newly minted token.\n /// @return tokenId Id of the newly minted token.\n function mint(address owner, string memory tokenURI) external returns (uint256 tokenId);\n\n /// @notice Destroy supply of a given tokenId by amount.\n /// @dev The msg.sender MUST be the owner.\n ///\n /// @param tokenId Item which have reduced supply.\n function burn(uint256 tokenId) external;\n}\n\n/// @notice Extension of ERC6909 Standard for tracking total supply\ninterface IERC6909TotalSupplyExt {\n /// @notice The totalSupply for a token id.\n ///\n /// @param tokenId Id of the token\n /// @return supply Total supply for a given `tokenId`\n function totalSupply(uint256 tokenId) external returns (uint256 supply);\n}\n\ninterface IERC6909Decimals {\n /// @notice Used to retrieve the decimals of an asset\n /// @dev address is used but the value corresponds to a AssetId\n function decimals(uint256 assetId) external view returns (uint8);\n}\n\ninterface IERC6909MetadataExt is IERC6909Decimals {\n /// @notice Used to retrieve the decimals of an asset\n /// @dev address is used but the value corresponds to a AssetId\n function decimals(uint256 assetId) external view returns (uint8);\n\n /// @notice Used to retrieve the name of an asset\n /// @dev address is used but the value corresponds to a AssetId\n function name(uint256 assetId) external view returns (string memory);\n\n /// @notice Used to retrieve the symbol of an asset\n /// @dev address is used but the value corresponds to a AssetId\n function symbol(uint256 assetId) external view returns (string memory);\n}\n\ninterface IERC6909Fungible is IERC6909 {\n /// @notice Mint new tokens for a specific tokenid and assign them to an owner\n ///\n /// @param owner Creates supply of a given `tokenId` by `amount` for owner.\n /// @param tokenId Id of the item\n /// @param amount Adds `amount` to the total supply of the given `tokenId`\n function mint(address owner, uint256 tokenId, uint256 amount) external;\n\n /// @notice Destroy supply of a given tokenId by amount.\n /// @dev The msg.sender MUST be the owner.\n ///\n /// @param owner Owner of the `tokenId`\n /// @param tokenId Id of the item.\n /// @param amount Subtract `amount` from the total supply of the given `tokenId`\n function burn(address owner, uint256 tokenId, uint256 amount) external;\n\n /// @notice Enforces a transfer from `spender` point of view.\n ///\n ///\n /// @param sender The owner of the `tokenId`\n /// @param receiver Address of the receiving party\n /// @param tokenId Token Id\n /// @param amount Amount to be transferred\n function authTransferFrom(address sender, address receiver, uint256 tokenId, uint256 amount)\n external\n returns (bool);\n}\n\n/// @dev A factory contract to deploy new collateral contracts implementing IERC6909.\ninterface IERC6909Factory {\n /// Events\n event NewTokenDeployment(address indexed owner, address instance);\n\n /// @notice Deploys new install of a contract that implements IERC6909.\n /// @dev Factory should deploy deterministically if possible.\n ///\n /// @param owner Owner of the deployed collateral contract which has initial full rights.\n /// @param salt Used to make a deterministic deployment.\n /// @return An address of the newly deployed contract.\n function deploy(address owner, bytes32 salt) external returns (address);\n\n /// @notice Generates a new deterministic address based on the owner and the salt.\n ///\n /// @param owner Owner of the deployed collateral contract which has initial full rights.\n /// @param salt Used to make a deterministic deployment.\n /// @return An address of the newly deployed contract.\n function previewAddress(address owner, bytes32 salt) external returns (address);\n}\n" + }, + "src/misc/interfaces/IERC7540.sol": { + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.5.0;\n\nimport {IRecoverable} from \"src/misc/interfaces/IRecoverable.sol\";\nimport {IERC7575, IERC165} from \"src/misc/interfaces/IERC7575.sol\";\n\ninterface IERC7540Operator {\n /**\n * @dev The event emitted when an operator is set.\n *\n * @param controller The address of the controller.\n * @param operator The address of the operator.\n * @param approved The approval status.\n */\n event OperatorSet(address indexed controller, address indexed operator, bool approved);\n\n /**\n * @dev Sets or removes an operator for the caller.\n *\n * @param operator The address of the operator.\n * @param approved The approval status.\n * @return Whether the call was executed successfully or not\n */\n function setOperator(address operator, bool approved) external returns (bool);\n\n /**\n * @dev Returns `true` if the `operator` is approved as an operator for an `controller`.\n *\n * @param controller The address of the controller.\n * @param operator The address of the operator.\n * @return status The approval status\n */\n function isOperator(address controller, address operator) external view returns (bool status);\n}\n\ninterface IERC7540Deposit is IERC7540Operator {\n event DepositRequest(\n address indexed controller, address indexed owner, uint256 indexed requestId, address sender, uint256 assets\n );\n /**\n * @dev Transfers assets from sender into the Vault and submits a Request for asynchronous deposit.\n *\n * - MUST support ERC-20 approve / transferFrom on asset as a deposit Request flow.\n * - MUST revert if all of assets cannot be requested for deposit.\n * - owner MUST be msg.sender unless some unspecified explicit approval is given by the caller,\n * approval of ERC-20 tokens from owner to sender is NOT enough.\n *\n * @param assets the amount of deposit assets to transfer from owner\n * @param controller the controller of the request who will be able to operate the request\n * @param owner the source of the deposit assets\n *\n * NOTE: most implementations will require pre-approval of the Vault with the Vault's underlying asset token.\n */\n\n function requestDeposit(uint256 assets, address controller, address owner) external returns (uint256 requestId);\n\n /**\n * @dev Returns the amount of requested assets in Pending state.\n *\n * - MUST NOT include any assets in Claimable state for deposit or mint.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT revert unless due to integer overflow caused by an unreasonably large input.\n */\n function pendingDepositRequest(uint256 requestId, address controller)\n external\n view\n returns (uint256 pendingAssets);\n\n /**\n * @dev Returns the amount of requested assets in Claimable state for the controller to deposit or mint.\n *\n * - MUST NOT include any assets in Pending state.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT revert unless due to integer overflow caused by an unreasonably large input.\n */\n function claimableDepositRequest(uint256 requestId, address controller)\n external\n view\n returns (uint256 claimableAssets);\n\n /**\n * @dev Mints shares Vault shares to receiver by claiming the Request of the controller.\n *\n * - MUST emit the Deposit event.\n * - controller MUST equal msg.sender unless the controller has approved the msg.sender as an operator.\n */\n function deposit(uint256 assets, address receiver, address controller) external returns (uint256 shares);\n\n /**\n * @dev Mints exactly shares Vault shares to receiver by claiming the Request of the controller.\n *\n * - MUST emit the Deposit event.\n * - controller MUST equal msg.sender unless the controller has approved the msg.sender as an operator.\n */\n function mint(uint256 shares, address receiver, address controller) external returns (uint256 assets);\n}\n\ninterface IERC7540Redeem is IERC7540Operator {\n event RedeemRequest(\n address indexed controller, address indexed owner, uint256 indexed requestId, address sender, uint256 assets\n );\n\n /**\n * @dev Assumes control of shares from sender into the Vault and submits a Request for asynchronous redeem.\n *\n * - MUST support a redeem Request flow where the control of shares is taken from sender directly\n * where msg.sender has ERC-20 approval over the shares of owner.\n * - MUST revert if all of shares cannot be requested for redeem.\n *\n * @param shares the amount of shares to be redeemed to transfer from owner\n * @param controller the controller of the request who will be able to operate the request\n * @param owner the source of the shares to be redeemed\n *\n * NOTE: most implementations will require pre-approval of the Vault with the Vault's share token.\n */\n function requestRedeem(uint256 shares, address controller, address owner) external returns (uint256 requestId);\n\n /**\n * @dev Returns the amount of requested shares in Pending state.\n *\n * - MUST NOT include any shares in Claimable state for redeem or withdraw.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT revert unless due to integer overflow caused by an unreasonably large input.\n */\n function pendingRedeemRequest(uint256 requestId, address controller)\n external\n view\n returns (uint256 pendingShares);\n\n /**\n * @dev Returns the amount of requested shares in Claimable state for the controller to redeem or withdraw.\n *\n * - MUST NOT include any shares in Pending state for redeem or withdraw.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT revert unless due to integer overflow caused by an unreasonably large input.\n */\n function claimableRedeemRequest(uint256 requestId, address controller)\n external\n view\n returns (uint256 claimableShares);\n}\n\ninterface IERC7887Deposit {\n event CancelDepositRequest(address indexed controller, uint256 indexed requestId, address sender);\n event CancelDepositClaim(\n address indexed controller, address indexed receiver, uint256 indexed requestId, address sender, uint256 assets\n );\n\n /**\n * @dev Submits a Request for cancelling the pending deposit Request\n *\n * - controller MUST be msg.sender unless some unspecified explicit approval is given by the caller,\n * approval of ERC-20 tokens from controller to sender is NOT enough.\n * - MUST set pendingCancelDepositRequest to `true` for the returned requestId after request\n * - MUST increase claimableCancelDepositRequest for the returned requestId after fulfillment\n * - SHOULD be claimable using `claimCancelDepositRequest`\n * Note: while `pendingCancelDepositRequest` is `true`, `requestDeposit` cannot be called\n */\n function cancelDepositRequest(uint256 requestId, address controller) external;\n\n /**\n * @dev Returns whether the deposit Request is pending cancelation\n *\n * - MUST NOT show any variations depending on the caller.\n */\n function pendingCancelDepositRequest(uint256 requestId, address controller)\n external\n view\n returns (bool isPending);\n\n /**\n * @dev Returns the amount of assets that were canceled from a deposit Request, and can now be claimed.\n *\n * - MUST NOT show any variations depending on the caller.\n */\n function claimableCancelDepositRequest(uint256 requestId, address controller)\n external\n view\n returns (uint256 claimableAssets);\n\n /**\n * @dev Claims the canceled deposit assets, and removes the pending cancelation Request\n *\n * - controller MUST be msg.sender unless some unspecified explicit approval is given by the caller,\n * approval of ERC-20 tokens from controller to sender is NOT enough.\n * - MUST set pendingCancelDepositRequest to `false` for the returned requestId after request\n * - MUST set claimableCancelDepositRequest to 0 for the returned requestId after fulfillment\n */\n function claimCancelDepositRequest(uint256 requestId, address receiver, address controller)\n external\n returns (uint256 assets);\n}\n\ninterface IERC7887Redeem {\n event CancelRedeemRequest(address indexed controller, uint256 indexed requestId, address sender);\n event CancelRedeemClaim(\n address indexed controller, address indexed receiver, uint256 indexed requestId, address sender, uint256 shares\n );\n\n /**\n * @dev Submits a Request for cancelling the pending redeem Request\n *\n * - controller MUST be msg.sender unless some unspecified explicit approval is given by the caller,\n * approval of ERC-20 tokens from controller to sender is NOT enough.\n * - MUST set pendingCancelRedeemRequest to `true` for the returned requestId after request\n * - MUST increase claimableCancelRedeemRequest for the returned requestId after fulfillment\n * - SHOULD be claimable using `claimCancelRedeemRequest`\n * Note: while `pendingCancelRedeemRequest` is `true`, `requestRedeem` cannot be called\n */\n function cancelRedeemRequest(uint256 requestId, address controller) external;\n\n /**\n * @dev Returns whether the redeem Request is pending cancelation\n *\n * - MUST NOT show any variations depending on the caller.\n */\n function pendingCancelRedeemRequest(uint256 requestId, address controller) external view returns (bool isPending);\n\n /**\n * @dev Returns the amount of shares that were canceled from a redeem Request, and can now be claimed.\n *\n * - MUST NOT show any variations depending on the caller.\n */\n function claimableCancelRedeemRequest(uint256 requestId, address controller)\n external\n view\n returns (uint256 claimableShares);\n\n /**\n * @dev Claims the canceled redeem shares, and removes the pending cancelation Request\n *\n * - controller MUST be msg.sender unless some unspecified explicit approval is given by the caller,\n * approval of ERC-20 tokens from controller to sender is NOT enough.\n * - MUST set pendingCancelRedeemRequest to `false` for the returned requestId after request\n * - MUST set claimableCancelRedeemRequest to 0 for the returned requestId after fulfillment\n */\n function claimCancelRedeemRequest(uint256 requestId, address receiver, address controller)\n external\n returns (uint256 shares);\n}\n\ninterface IERC7741 {\n /**\n * @dev Grants or revokes permissions for `operator` to manage Requests on behalf of the\n * `msg.sender`, using an [EIP-712](./eip-712.md) signature.\n */\n function authorizeOperator(\n address controller,\n address operator,\n bool approved,\n bytes32 nonce,\n uint256 deadline,\n bytes memory signature\n ) external returns (bool);\n\n /**\n * @dev Revokes the given `nonce` for `msg.sender` as the `owner`.\n */\n function invalidateNonce(bytes32 nonce) external;\n\n /**\n * @dev Returns whether the given `nonce` has been used for the `controller`.\n */\n function authorizations(address controller, bytes32 nonce) external view returns (bool used);\n\n /**\n * @dev Returns the `DOMAIN_SEPARATOR` as defined according to EIP-712. The `DOMAIN_SEPARATOR\n * should be unique to the contract and chain to prevent replay attacks from other domains,\n * and satisfy the requirements of EIP-712, but is otherwise unconstrained.\n */\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\ninterface IERC7714 {\n /**\n * @dev Returns `true` if the `user` is permissioned to interact with the contract.\n */\n function isPermissioned(address controller) external view returns (bool);\n}\n" + }, + "src/misc/interfaces/IERC7575.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\ninterface IERC7575 is IERC165 {\n event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares);\n event Withdraw(\n address indexed sender, address indexed receiver, address indexed owner, uint256 assets, uint256 shares\n );\n\n /**\n * @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.\n *\n * - MUST be an ERC-20 token contract.\n * - MUST NOT revert.\n */\n function asset() external view returns (address assetTokenAddress);\n\n /**\n * @dev Returns the address of the share token\n *\n * - MUST be an ERC-20 token contract.\n * - MUST NOT revert.\n */\n function share() external view returns (address shareTokenAddress);\n\n /**\n * @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal\n * scenario where all the conditions are met.\n *\n * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.\n * - MUST NOT revert.\n *\n * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the\n * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and\n * from.\n */\n function convertToShares(uint256 assets) external view returns (uint256 shares);\n\n /**\n * @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal\n * scenario where all the conditions are met.\n *\n * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.\n * - MUST NOT revert.\n *\n * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the\n * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and\n * from.\n */\n function convertToAssets(uint256 shares) external view returns (uint256 assets);\n\n /**\n * @dev Returns the total amount of the underlying asset that is “managed” by Vault.\n *\n * - SHOULD include any compounding that occurs from yield.\n * - MUST be inclusive of any fees that are charged against assets in the Vault.\n * - MUST NOT revert.\n */\n function totalAssets() external view returns (uint256 totalManagedAssets);\n\n /**\n * @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,\n * through a deposit call.\n *\n * - MUST return a limited value if receiver is subject to some deposit limit.\n * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.\n * - MUST NOT revert.\n */\n function maxDeposit(address receiver) external view returns (uint256 maxAssets);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given\n * current on-chain conditions.\n *\n * - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit\n * call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called\n * in the same transaction.\n * - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the\n * deposit would be accepted, regardless if the user has enough tokens approved, etc.\n * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by depositing.\n */\n function previewDeposit(uint256 assets) external view returns (uint256 shares);\n\n /**\n * @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens.\n *\n * - MUST emit the Deposit event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n * deposit execution, and are accounted for during deposit.\n * - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not\n * approving enough underlying tokens to the Vault contract, etc).\n *\n * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.\n */\n function deposit(uint256 assets, address receiver) external returns (uint256 shares);\n\n /**\n * @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.\n * - MUST return a limited value if receiver is subject to some mint limit.\n * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.\n * - MUST NOT revert.\n */\n function maxMint(address receiver) external view returns (uint256 maxShares);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given\n * current on-chain conditions.\n *\n * - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call\n * in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the\n * same transaction.\n * - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint\n * would be accepted, regardless if the user has enough tokens approved, etc.\n * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by minting.\n */\n function previewMint(uint256 shares) external view returns (uint256 assets);\n\n /**\n * @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.\n *\n * - MUST emit the Deposit event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint\n * execution, and are accounted for during mint.\n * - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not\n * approving enough underlying tokens to the Vault contract, etc).\n *\n * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.\n */\n function mint(uint256 shares, address receiver) external returns (uint256 assets);\n\n /**\n * @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the\n * Vault, through a withdraw call.\n *\n * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.\n * - MUST NOT revert.\n */\n function maxWithdraw(address owner) external view returns (uint256 maxAssets);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,\n * given current on-chain conditions.\n *\n * - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw\n * call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if\n * called\n * in the same transaction.\n * - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though\n * the withdrawal would be accepted, regardless if the user has enough shares, etc.\n * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by depositing.\n */\n function previewWithdraw(uint256 assets) external view returns (uint256 shares);\n\n /**\n * @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver.\n *\n * - MUST emit the Withdraw event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n * withdraw execution, and are accounted for during withdraw.\n * - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner\n * not having enough shares, etc).\n *\n * Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.\n * Those methods should be performed separately.\n */\n function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares);\n\n /**\n * @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault,\n * through a redeem call.\n *\n * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.\n * - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock.\n * - MUST NOT revert.\n */\n function maxRedeem(address owner) external view returns (uint256 maxShares);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block,\n * given current on-chain conditions.\n *\n * - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call\n * in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the\n * same transaction.\n * - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the\n * redemption would be accepted, regardless if the user has enough shares, etc.\n * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by redeeming.\n */\n function previewRedeem(uint256 shares) external view returns (uint256 assets);\n\n /**\n * @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver.\n *\n * - MUST emit the Withdraw event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n * redeem execution, and are accounted for during redeem.\n * - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner\n * not having enough shares, etc).\n *\n * NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed.\n * Those methods should be performed separately.\n */\n function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets);\n}\n\ninterface IERC7575Share is IERC165 {\n event VaultUpdate(address indexed asset, address vault);\n\n /**\n * @dev Returns the address of the Vault for the given asset.\n *\n * @param asset the ERC-20 token to deposit with into the Vault\n */\n function vault(address asset) external view returns (address);\n}\n" + }, + "src/misc/interfaces/IERC7726.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\n/// [ERC-7726](https://eips.ethereum.org/EIPS/eip-7726): Common Quote Oracle\n/// Interface for asset conversions.\ninterface IERC7726 {\n /// @notice Returns the value of baseAmount of base in quote terms, e.g. 10 ETH (base) in USDC (quote).\n /// @param base The asset in which the baseAmount is denominated in\n /// @param quote The asset in which the user needs to value the baseAmount\n /// @param baseAmount The amount of base in base terms.\n function getQuote(uint256 baseAmount, address base, address quote) external view returns (uint256 quoteAmount);\n}\n" + }, + "src/misc/interfaces/IIdentityValuation.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IERC7726} from \"src/misc/interfaces/IERC7726.sol\";\n\n/// @notice An IERC7726 valuation that always values 1:1.\ninterface IIdentityValuation is IERC7726 {}\n" + }, + "src/misc/interfaces/IMulticall.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\n/// @notice Allows to call several calls of the same contract in a single transaction\ninterface IMulticall {\n /// @notice Dispatched when an empty revert is dispatched in a method in the multicall\n error CallFailedWithEmptyRevert();\n\n /// @notice Allows caller to execute multiple (batched) messages calls in one transaction.\n /// @param data An array of encoded methods of the same contract.\n /// @dev No reentrant execution is allowed.\n /// If one call fails, it reverts the whole transaction.\n /// In order to provide the correct value for functions that require top up,\n /// the caller must estimate separately, in advance, how much each of the message call will cost.\n /// The `msg.value` when calling this method must be the sum of all estimates.\n function multicall(bytes[] calldata data) external payable;\n}\n" + }, + "src/misc/interfaces/IRecoverable.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\naddress constant ETH_ADDRESS = address(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);\n\ninterface IRecoverable {\n /// @notice Used to recover any ERC-20 token.\n /// @dev This method is called only by authorized entities\n /// @param token It could be 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee\n /// to recover locked native ETH or token compatible with ERC20.\n /// @param to Receiver of the funds\n /// @param amount Amount to send to the receiver.\n function recoverTokens(address token, address to, uint256 amount) external;\n\n /// @notice Used to recover any ERC-20 or ERC-6909 token.\n /// @dev This method is called only by authorized entities\n /// @param token It could be 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee\n /// to recover locked native ETH or token compatible with ERC20 or ERC6909.\n /// @param tokenId The token id, i.e. non-zero if the underlying token is ERC6909 and else zero.\n /// @param to Receiver of the funds\n /// @param amount Amount to send to the receiver.\n function recoverTokens(address token, uint256 tokenId, address to, uint256 amount) external;\n}\n" + }, + "src/misc/libraries/ArrayLib.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\n/// @title ArrayLib\nlibrary ArrayLib {\n error InvalidValues();\n\n function countNonZeroValues(uint16[8] memory arr) internal pure returns (uint8 count) {\n uint256 elementsCount = arr.length;\n for (uint256 i; i < elementsCount; i++) {\n if (arr[i] != 0) ++count;\n }\n }\n\n function decreaseFirstNValues(uint16[8] storage arr, uint8 numValues) internal {\n uint256 elementsCount = arr.length;\n for (uint256 i; i < elementsCount; i++) {\n if (numValues == 0) return;\n\n if (arr[i] != 0) {\n arr[i] -= 1;\n numValues--;\n }\n }\n\n require(numValues == 0, InvalidValues());\n }\n\n function isEmpty(uint16[8] memory arr) internal pure returns (bool) {\n uint256 elementsCount = arr.length;\n for (uint256 i; i < elementsCount; i++) {\n if (arr[i] != 0) return false;\n }\n return true;\n }\n}\n" + }, + "src/misc/libraries/BitmapLib.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\n/// @title BitmapLib\nlibrary BitmapLib {\n function setBit(uint128 bitmap, uint128 index, bool isTrue) internal pure returns (uint128) {\n if (isTrue) {\n return bitmap | (uint128(1) << index);\n }\n\n return bitmap & ~(uint128(1) << index);\n }\n\n function getBit(uint128 bitmap, uint128 index) internal pure returns (bool) {\n uint128 bitAtIndex = uint128(bitmap & (1 << index));\n return bitAtIndex != 0;\n }\n}\n" + }, + "src/misc/libraries/BytesLib.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\n/// @title Bytes Lib\n/// @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity.\n/// The library lets you concatenate, slice and type cast bytes arrays both in memory and storage.\n/// @author Modified from Solidity Bytes Arrays Utils v0.8.0\nlibrary BytesLib {\n error SliceOverflow();\n error SliceOutOfBounds();\n\n function sliceZeroPadded(bytes memory _bytes, uint256 _start, uint256 _length)\n internal\n pure\n returns (bytes memory)\n {\n require(_length + 31 >= _length, SliceOverflow());\n\n bytes memory tempBytes;\n\n assembly {\n switch iszero(_length)\n case 0 {\n // Get a location of some free memory and store it in tempBytes as\n // Solidity does for memory variables.\n tempBytes := mload(0x40)\n\n // The first word of the slice result is potentially a partial\n // word read from the original array. To read it, we calculate\n // the length of that partial word and start copying that many\n // bytes into the array. The first word we copy will start with\n // data we don't care about, but the last `lengthmod` bytes will\n // land at the beginning of the contents of the new array. When\n // we're done copying, we overwrite the full first word with\n // the actual length of the slice.\n let lengthmod := and(_length, 31)\n\n // The multiplication in the next line is necessary\n // because when slicing multiples of 32 bytes (lengthmod == 0)\n // the following copy loop was copying the origin's length\n // and then ending prematurely not copying everything it should.\n let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))\n let end := add(mc, _length)\n\n for {\n // The multiplication in the next line has the same exact purpose\n // as the one above.\n let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)\n } lt(mc, end) {\n mc := add(mc, 0x20)\n cc := add(cc, 0x20)\n } { mstore(mc, mload(cc)) }\n\n mstore(tempBytes, _length)\n\n //update free-memory pointer\n //allocating the array padded to 32 bytes like the compiler does now\n mstore(0x40, and(add(mc, 31), not(31)))\n }\n //if we want a zero-length slice let's just return a zero-length array\n default {\n tempBytes := mload(0x40)\n //zero out the 32 bytes slice we are about to return\n //we need to do it because Solidity does not garbage collect\n mstore(tempBytes, 0)\n\n mstore(0x40, add(tempBytes, 0x20))\n }\n }\n\n return tempBytes;\n }\n\n function slice(bytes memory _bytes, uint256 _start, uint256 _length) internal pure returns (bytes memory) {\n require(_bytes.length >= _start + _length, SliceOutOfBounds());\n return sliceZeroPadded(_bytes, _start, _length);\n }\n\n function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) {\n require(_bytes.length >= _start + 20, SliceOutOfBounds());\n address tempAddress;\n\n assembly {\n tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000)\n }\n\n return tempAddress;\n }\n\n function toUint8(bytes memory _bytes, uint256 _start) internal pure returns (uint8) {\n require(_bytes.length >= _start + 1, SliceOutOfBounds());\n uint8 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x1), _start))\n }\n\n return tempUint;\n }\n\n function toUint16(bytes memory _bytes, uint256 _start) internal pure returns (uint16) {\n require(_bytes.length >= _start + 2, SliceOutOfBounds());\n uint16 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x2), _start))\n }\n\n return tempUint;\n }\n\n function toUint32(bytes memory _bytes, uint256 _start) internal pure returns (uint32) {\n require(_bytes.length >= _start + 4, SliceOutOfBounds());\n uint32 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x4), _start))\n }\n\n return tempUint;\n }\n\n function toUint64(bytes memory _bytes, uint256 _start) internal pure returns (uint64) {\n require(_bytes.length >= _start + 8, SliceOutOfBounds());\n uint64 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x8), _start))\n }\n\n return tempUint;\n }\n\n function toUint128(bytes memory _bytes, uint256 _start) internal pure returns (uint128) {\n require(_bytes.length >= _start + 16, SliceOutOfBounds());\n uint128 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x10), _start))\n }\n\n return tempUint;\n }\n\n function toUint256(bytes memory _bytes, uint256 _start) internal pure returns (uint256) {\n require(_bytes.length >= _start + 32, SliceOutOfBounds());\n uint256 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x20), _start))\n }\n\n return tempUint;\n }\n\n function toBytes32(bytes memory _bytes, uint256 _start) internal pure returns (bytes32) {\n require(_bytes.length >= _start + 32, SliceOutOfBounds());\n bytes32 tempBytes32;\n\n assembly {\n tempBytes32 := mload(add(add(_bytes, 0x20), _start))\n }\n\n return tempBytes32;\n }\n\n function toBytes16(bytes memory _bytes, uint256 _start) internal pure returns (bytes16) {\n require(_bytes.length >= _start + 16, SliceOutOfBounds());\n bytes16 tempBytes16;\n\n assembly {\n tempBytes16 := mload(add(add(_bytes, 0x20), _start))\n }\n\n return tempBytes16;\n }\n\n function toBool(bytes memory _bytes, uint256 _start) internal pure returns (bool) {\n require(_bytes.length > _start, SliceOutOfBounds());\n return _bytes[_start] != 0;\n }\n}\n" + }, + "src/misc/libraries/CastLib.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\n/// @title CastLib\nlibrary CastLib {\n function toAddressLeftPadded(bytes32 addr) internal pure returns (address) {\n require(bytes12(addr) == 0, \"First 12 bytes should be zero\");\n return address(uint160(uint256(addr)));\n }\n\n function toBytes32LeftPadded(address addr) internal pure returns (bytes32) {\n return bytes32(uint256(uint160(addr)));\n }\n\n function toAddress(bytes32 addr) internal pure returns (address) {\n require(uint96(uint256(addr)) == 0, \"Input should be 20 bytes\");\n return address(bytes20(addr));\n }\n\n function toString(address addr) internal pure returns (string memory) {\n return string(abi.encodePacked(addr));\n }\n\n function toBytes32(address addr) internal pure returns (bytes32) {\n return bytes32(bytes20(addr));\n }\n\n /// @dev Adds zero padding\n function toBytes32(string memory source) internal pure returns (bytes32) {\n return bytes32(bytes(source));\n }\n\n /// @dev Removes zero padding\n function bytes128ToString(bytes memory _bytes128) internal pure returns (string memory) {\n require(_bytes128.length == 128, \"Input should be 128 bytes\");\n\n uint8 i = 0;\n while (i < 128 && _bytes128[i] != 0) {\n i++;\n }\n\n bytes memory bytesArray = new bytes(i);\n\n for (uint8 j; j < i; j++) {\n bytesArray[j] = _bytes128[j];\n }\n\n return string(bytesArray);\n }\n\n function toString(bytes32 _bytes32) internal pure returns (string memory) {\n uint8 i = 0;\n while (i < 32 && _bytes32[i] != 0) {\n i++;\n }\n bytes memory bytesArray = new bytes(i);\n for (i = 0; i < 32 && _bytes32[i] != 0; i++) {\n bytesArray[i] = _bytes32[i];\n }\n return string(bytesArray);\n }\n}\n" + }, + "src/misc/libraries/EIP712Lib.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\n/// @title EIP712 Lib\nlibrary EIP712Lib {\n // keccak256(\"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\")\n bytes32 public constant EIP712_DOMAIN_TYPEHASH = 0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f;\n\n function calculateDomainSeparator(bytes32 nameHash, bytes32 versionHash) internal view returns (bytes32) {\n return keccak256(abi.encode(EIP712_DOMAIN_TYPEHASH, nameHash, versionHash, block.chainid, address(this)));\n }\n}\n" + }, + "src/misc/libraries/MathLib.sol": { + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.28;\n\nlibrary MathLib {\n enum Rounding {\n Down, // Toward negative infinity\n Up, // Toward infinity\n Zero // Toward zero\n\n }\n\n error MulDiv_Overflow();\n error Uint8_Overflow();\n error Uint32_Overflow();\n error Uint64_Overflow();\n error Uint128_Overflow();\n error Int128_Overflow();\n\n uint256 public constant One27 = 10 ** 27;\n\n /// @notice Returns x^n with rounding precision of base\n ///\n /// @dev Source: https://github.com/makerdao/dss/blob/fa4f6630afb0624d04a003e920b0d71a00331d98/src/jug.sol#L62\n ///\n /// @param x The base value which should be exponentiated\n /// @param n The exponent\n /// @param base The scaling base, typically used for fix-point calculations\n function rpow(uint256 x, uint256 n, uint256 base) public pure returns (uint256 z) {\n assembly {\n switch x\n case 0 {\n switch n\n case 0 { z := base }\n default { z := 0 }\n }\n default {\n switch mod(n, 2)\n case 0 { z := base }\n default { z := x }\n let half := div(base, 2) // for rounding.\n for { n := div(n, 2) } n { n := div(n, 2) } {\n let xx := mul(x, x)\n if iszero(eq(div(xx, x), x)) { revert(0, 0) }\n let xxRound := add(xx, half)\n if lt(xxRound, xx) { revert(0, 0) }\n x := div(xxRound, base)\n if mod(n, 2) {\n let zx := mul(z, x)\n if and(iszero(iszero(x)), iszero(eq(div(zx, x), z))) { revert(0, 0) }\n let zxRound := add(zx, half)\n if lt(zxRound, zx) { revert(0, 0) }\n z := div(zxRound, base)\n }\n }\n }\n }\n }\n\n /// @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or\n /// denominator == 0\n /// @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\n /// with further edits by Uniswap Labs also under MIT license.\n // slither-disable-start divide-before-multiply\n function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {\n unchecked {\n // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\n // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\n // variables such that product = prod1 * 2^256 + prod0.\n uint256 prod0; // Least significant 256 bits of the product\n uint256 prod1; // Most significant 256 bits of the product\n assembly {\n let mm := mulmod(x, y, not(0))\n prod0 := mul(x, y)\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n }\n\n // Handle non-overflow cases, 256 by 256 division.\n if (prod1 == 0) {\n // Solidity will revert if denominator == 0, unlike the div opcode on its own.\n // The surrounding unchecked block does not change this fact.\n // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.\n return prod0 / denominator;\n }\n\n // Make sure the result is less than 2^256. Also prevents denominator == 0.\n require(denominator > prod1, MulDiv_Overflow());\n\n ///////////////////////////////////////////////\n // 512 by 256 division.\n ///////////////////////////////////////////////\n\n // Make division exact by subtracting the remainder from [prod1 prod0].\n uint256 remainder;\n assembly {\n // Compute remainder using mulmod.\n remainder := mulmod(x, y, denominator)\n\n // Subtract 256 bit number from 512 bit number.\n prod1 := sub(prod1, gt(remainder, prod0))\n prod0 := sub(prod0, remainder)\n }\n\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator.\n // Always >= 1.\n // See https://cs.stackexchange.com/q/138556/92363.\n\n // Does not overflow because the denominator cannot be zero at this stage in the function.\n uint256 twos = denominator & (~denominator + 1);\n assembly {\n // Divide denominator by twos.\n denominator := div(denominator, twos)\n\n // Divide [prod1 prod0] by twos.\n prod0 := div(prod0, twos)\n\n // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\n twos := add(div(sub(0, twos), twos), 1)\n }\n\n // Shift in bits from prod1 into prod0.\n prod0 |= prod1 * twos;\n\n // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\n // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\n // four bits. That is, denominator * inv = 1 mod 2^4.\n uint256 inverse = (3 * denominator) ^ 2;\n\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also\n // works\n // in modular arithmetic, doubling the correct bits in each step.\n inverse *= 2 - denominator * inverse; // inverse mod 2^8\n inverse *= 2 - denominator * inverse; // inverse mod 2^16\n inverse *= 2 - denominator * inverse; // inverse mod 2^32\n inverse *= 2 - denominator * inverse; // inverse mod 2^64\n inverse *= 2 - denominator * inverse; // inverse mod 2^128\n inverse *= 2 - denominator * inverse; // inverse mod 2^256\n\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\n // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\n // is no longer required.\n result = prod0 * inverse;\n return result;\n }\n }\n // slither-disable-end divide-before-multiply\n\n /// @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\n function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {\n uint256 result = mulDiv(x, y, denominator);\n if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\n result += 1;\n }\n return result;\n }\n\n /// @notice Safe type conversion from uint256 to uint8.\n function toUint8(uint256 value) internal pure returns (uint8) {\n require(value <= type(uint8).max, Uint8_Overflow());\n return uint8(value);\n }\n\n function toUint32(uint256 value) internal pure returns (uint32) {\n require(value <= type(uint32).max, Uint32_Overflow());\n return uint32(value);\n }\n\n function toUint64(uint256 value) internal pure returns (uint64) {\n require(value <= type(uint64).max, Uint64_Overflow());\n return uint64(value);\n }\n\n /// @notice Safe type conversion from uint256 to uint128.\n function toUint128(uint256 value) internal pure returns (uint128) {\n require(value <= type(uint128).max, Uint128_Overflow());\n return uint128(value);\n }\n\n /// @notice Returns the smallest of two numbers.\n function min(uint256 a, uint256 b) internal pure returns (uint256) {\n return a > b ? b : a;\n }\n\n /// @notice Returns the largest of two numbers.\n function max(uint256 a, uint256 b) internal pure returns (uint256) {\n return a > b ? a : b;\n }\n}\n" + }, + "src/misc/libraries/SafeTransferLib.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IERC20} from \"src/misc/interfaces/IERC20.sol\";\n\n/// @title Safe Transfer Lib\n/// @author Modified from Uniswap v3 Periphery (libraries/TransferHelper.sol)\nlibrary SafeTransferLib {\n error NoCode();\n error SafeTransferFromFailed();\n error SafeTransferFailed();\n error SafeApproveFailed();\n error SafeTransferEthFailed();\n\n /// @notice Transfers tokens from the targeted address to the given destination\n /// @notice Errors if transfer fails\n /// @param token The contract address of the token to be transferred\n /// @param from The originating address from which the tokens will be transferred\n /// @param to The destination address of the transfer\n /// @param value The amount to be transferred\n function safeTransferFrom(address token, address from, address to, uint256 value) internal {\n require(address(token).code.length > 0, NoCode());\n\n (bool success, bytes memory data) = token.call(abi.encodeCall(IERC20.transferFrom, (from, to, value)));\n require(success && (data.length == 0 || abi.decode(data, (bool))), SafeTransferFromFailed());\n }\n\n /// @notice Transfers tokens from msg.sender to a recipient\n /// @dev Errors if transfer fails\n /// @param token The contract address of the token which will be transferred\n /// @param to The recipient of the transfer\n /// @param value The value of the transfer\n function safeTransfer(address token, address to, uint256 value) internal {\n require(address(token).code.length > 0, NoCode());\n\n (bool success, bytes memory data) = token.call(abi.encodeCall(IERC20.transfer, (to, value)));\n require(success && (data.length == 0 || abi.decode(data, (bool))), SafeTransferFailed());\n }\n\n /// @notice Approves the stipulated contract to spend the given allowance in the given token\n /// @dev Errors if approval fails\n /// @param token The contract address of the token to be approved\n /// @param to The target of the approval\n /// @param value The amount of the given token the target will be allowed to spend\n function safeApprove(address token, address to, uint256 value) internal {\n require(address(token).code.length > 0, NoCode());\n\n (bool success, bytes memory data) = token.call(abi.encodeCall(IERC20.approve, (to, value)));\n require(success && (data.length == 0 || abi.decode(data, (bool))), SafeApproveFailed());\n }\n\n /// @notice Transfers ETH to the recipient address\n /// @dev Fails with `STE`\n /// @dev Make sure that method that is using this function is protected from reentrancy\n /// @param to The destination of the transfer\n /// @param value The value to be transferred\n function safeTransferETH(address to, uint256 value) internal {\n (bool success,) = to.call{value: value}(new bytes(0));\n require(success, SafeTransferEthFailed());\n }\n}\n" + }, + "src/misc/libraries/SignatureLib.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\ninterface IERC1271 {\n function isValidSignature(bytes32, bytes memory) external view returns (bytes4);\n}\n\n/// @title Signature Lib\nlibrary SignatureLib {\n error InvalidSigner();\n\n function isValidSignature(address signer, bytes32 digest, bytes memory signature)\n internal\n view\n returns (bool valid)\n {\n require(signer != address(0), InvalidSigner());\n\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n if (signer == ecrecover(digest, v, r, s)) {\n return true;\n }\n }\n\n if (signer.code.length > 0) {\n (bool success, bytes memory result) =\n signer.staticcall(abi.encodeCall(IERC1271.isValidSignature, (digest, signature)));\n valid =\n (success && result.length == 32 && abi.decode(result, (bytes4)) == IERC1271.isValidSignature.selector);\n }\n }\n}\n" + }, + "src/misc/libraries/StringLib.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nlibrary StringLib {\n function isEmpty(string memory value) internal pure returns (bool) {\n return bytes(value).length == 0;\n }\n}\n" + }, + "src/misc/libraries/TransientArrayLib.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {TransientStorageLib} from \"src/misc/libraries/TransientStorageLib.sol\";\n\n/// @title TransientArrayLib\nlibrary TransientArrayLib {\n using TransientStorageLib for bytes32;\n\n function push(bytes32 key, bytes32 value) internal {\n bytes32 lengthSlot = keccak256(abi.encodePacked(key, type(uint256).max));\n uint256 length_ = lengthSlot.tloadUint256();\n lengthSlot.tstore(length_ + 1);\n\n bytes32 slot = keccak256(abi.encodePacked(key, length_));\n slot.tstore(value);\n }\n\n function getBytes32(bytes32 key) internal view returns (bytes32[] memory) {\n uint256 length_ = length(key);\n\n bytes32[] memory data = new bytes32[](length_);\n for (uint256 i = 0; i < length_; i++) {\n bytes32 slot = keccak256(abi.encodePacked(key, i));\n data[i] = slot.tloadBytes32();\n }\n\n return data;\n }\n\n function length(bytes32 key) internal view returns (uint256) {\n return keccak256(abi.encodePacked(key, type(uint256).max)).tloadUint256();\n }\n\n function clear(bytes32 key) internal {\n bytes32 lengthSlot = keccak256(abi.encodePacked(key, type(uint256).max));\n lengthSlot.tstore(uint256(0));\n }\n}\n" + }, + "src/misc/libraries/TransientBytesLib.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\nimport {TransientStorageLib} from \"src/misc/libraries/TransientStorageLib.sol\";\n\n/// @title TransientBytesLib\nlibrary TransientBytesLib {\n using TransientStorageLib for bytes32;\n using BytesLib for bytes;\n\n function append(bytes32 key, bytes memory value) internal {\n bytes32 lengthSlot = keccak256(abi.encodePacked(key, type(uint256).max));\n uint256 prevLength = lengthSlot.tloadUint256();\n\n uint256 startChunk = prevLength / 32;\n uint256 offset = prevLength % 32;\n\n lengthSlot.tstore(prevLength + value.length);\n\n bytes32 joinSlot = keccak256(abi.encodePacked(key, startChunk));\n bytes memory firstPart = abi.encodePacked(joinSlot.tloadBytes32()).sliceZeroPadded(0, offset);\n bytes memory secondPart = value.sliceZeroPadded(0, 32 - offset);\n joinSlot.tstore(bytes32(bytes.concat(firstPart, secondPart)));\n\n uint256 valueOffset = 32 - offset;\n uint256 chunkIndex = startChunk + 1;\n for (; valueOffset < value.length; chunkIndex++) {\n bytes32 slot = keccak256(abi.encodePacked(key, chunkIndex));\n slot.tstore(bytes32(value.sliceZeroPadded(valueOffset, 32)));\n valueOffset += 32;\n }\n }\n\n function get(bytes32 key) internal view returns (bytes memory) {\n bytes memory data;\n uint256 length = keccak256(abi.encodePacked(key, type(uint256).max)).tloadUint256();\n if (length == 0) return data;\n\n uint256 chunks = length / 32 + 1;\n for (uint256 i = 0; i < chunks; i++) {\n bytes32 slot = keccak256(abi.encodePacked(key, i));\n data = bytes.concat(data, slot.tloadBytes32());\n }\n\n return data.slice(0, length);\n }\n\n function clear(bytes32 key) internal {\n bytes32 lengthSlot = keccak256(abi.encodePacked(key, type(uint256).max));\n lengthSlot.tstore(uint256(0));\n }\n}\n" + }, + "src/misc/libraries/TransientStorageLib.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\n/// @title TransientStorageLib\nlibrary TransientStorageLib {\n function tstore(bytes32 slot, address value) internal {\n assembly (\"memory-safe\") {\n tstore(slot, value)\n }\n }\n\n function tstore(bytes32 slot, uint256 value) internal {\n assembly (\"memory-safe\") {\n tstore(slot, value)\n }\n }\n\n function tstore(bytes32 slot, bytes32 value) internal {\n assembly (\"memory-safe\") {\n tstore(slot, value)\n }\n }\n\n function tstore(bytes32 slot, bool value) internal {\n assembly (\"memory-safe\") {\n tstore(slot, value)\n }\n }\n\n function tloadAddress(bytes32 slot) internal view returns (address value) {\n assembly (\"memory-safe\") {\n value := tload(slot)\n }\n }\n\n function tloadUint128(bytes32 slot) internal view returns (uint128 value) {\n assembly (\"memory-safe\") {\n value := tload(slot)\n }\n }\n\n function tloadUint256(bytes32 slot) internal view returns (uint256 value) {\n assembly (\"memory-safe\") {\n value := tload(slot)\n }\n }\n\n function tloadBytes32(bytes32 slot) internal view returns (bytes32 value) {\n assembly (\"memory-safe\") {\n value := tload(slot)\n }\n }\n\n function tloadBool(bytes32 slot) internal view returns (bool value) {\n assembly (\"memory-safe\") {\n value := tload(slot)\n }\n }\n}\n" + }, + "src/misc/types/D18.sol": { + "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.28;\n\n// Small library to handle fixed point number operations with 18 decimals with static typing support.\n\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\n\ntype D18 is uint128;\n\nusing MathLib for uint256;\n\n/// @dev add two D18 types\nfunction add(D18 d1, D18 d2) pure returns (D18) {\n return D18.wrap(D18.unwrap(d1) + D18.unwrap(d2));\n}\n\n/// @dev substract two D18 types\nfunction sub(D18 d1, D18 d2) pure returns (D18) {\n return D18.wrap(D18.unwrap(d1) - D18.unwrap(d2));\n}\n\n/// @dev Divides one D18 by another one while retaining precision:\n/// - nominator (decimal): 50e18\n/// - denominator (decimal): 2e19\n/// - result (decimal): 25e17\nfunction divD18(D18 d1, D18 d2) pure returns (D18) {\n return D18.wrap(MathLib.mulDiv(D18.unwrap(d1), 1e18, D18.unwrap(d2)).toUint128());\n}\n\n/// @dev Multiplies one D18 with another one while retaining precision:\n/// - value1 (decimal): 50e18\n/// - value2 (decimal): 2e19\n/// - result (decimal): 100e19\nfunction mulD18(D18 d1, D18 d2) pure returns (D18) {\n return D18.wrap(MathLib.mulDiv(D18.unwrap(d1), D18.unwrap(d2), 1e18).toUint128());\n}\n\n/// @dev sugar for getting the inner representation of a D18\nfunction inner(D18 d1) pure returns (uint128) {\n return D18.unwrap(d1);\n}\n\n/// @dev Returns the reciprocal of a D18 decimal, i.e. 1 / d.\n/// Example: if d = 2.0 (2e18 internally), reciprocal(d) = 0.5 (5e17 internally).\nfunction reciprocal(D18 d) pure returns (D18) {\n uint128 val = D18.unwrap(d);\n require(val != 0, \"D18/division-by-zero\");\n return d18(1e18, val);\n}\n\n/// @dev Multiplies a decimal by an integer. i.e:\n/// - d (decimal): 1_500_000_000_000_000_000\n/// - value (integer): 4_000_000_000_000_000_000\n/// - result (integer): 6_000_000_000_000_000_000\nfunction mulUint128(D18 d, uint128 value, MathLib.Rounding rounding) pure returns (uint128) {\n return MathLib.mulDiv(D18.unwrap(d), value, 1e18, rounding).toUint128();\n}\n\n/// @dev Multiplies a decimal by an integer. i.e:\n/// - d (decimal): 1_500_000_000_000_000_000\n/// - value (integer): 4_000_000_000_000_000_000\n/// - result (integer): 6_000_000_000_000_000_000\nfunction mulUint256(D18 d, uint256 value, MathLib.Rounding rounding) pure returns (uint256) {\n return MathLib.mulDiv(D18.unwrap(d), value, 1e18, rounding);\n}\n\n/// @dev Divides an integer by a decimal, i.e.\n/// @dev Same as mulDiv for integers, i.e:\n/// - d (decimal): 2_000_000_000_000_000_000\n/// - value (integer): 100_000_000_000_000_000_000\n/// - result (integer): 50_000_000_000_000_000_000\nfunction reciprocalMulUint128(D18 d, uint128 value, MathLib.Rounding rounding) pure returns (uint128) {\n return MathLib.mulDiv(value, 1e18, d.inner(), rounding).toUint128();\n}\n\n/// @dev Divides an integer by a decimal, i.e.\n/// @dev Same as mulDiv for integers, i.e:\n/// - d (decimal): 2_000_000_000_000_000_000\n/// - value (integer): 100_000_000_000_000_000_000\n/// - result (integer): 50_000_000_000_000_000_000\nfunction reciprocalMulUint256(D18 d, uint256 value, MathLib.Rounding rounding) pure returns (uint256) {\n return MathLib.mulDiv(value, 1e18, d.inner(), rounding);\n}\n\n/// @dev Easy way to construct a decimal number\nfunction d18(uint128 value) pure returns (D18) {\n return D18.wrap(value);\n}\n\n/// @dev Easy way to construct a decimal number\nfunction d18(uint128 num, uint128 den) pure returns (D18) {\n return D18.wrap(MathLib.mulDiv(num, 1e18, den).toUint128());\n}\n\nfunction eq(D18 a, D18 b) pure returns (bool) {\n return D18.unwrap(a) == D18.unwrap(b);\n}\n\nfunction raw(D18 d) pure returns (uint128) {\n return D18.unwrap(d);\n}\n\nusing {\n add as +,\n sub as -,\n divD18 as /,\n inner,\n eq,\n mulD18 as *,\n mulUint128,\n mulUint256,\n reciprocalMulUint128,\n reciprocalMulUint256,\n reciprocal,\n raw\n} for D18 global;\n" + }, + "src/vaults/AsyncRequestManager.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\nimport {D18, d18} from \"src/misc/types/D18.sol\";\n\nimport {MessageLib} from \"src/common/libraries/MessageLib.sol\";\nimport {IVaultMessageSender} from \"src/common/interfaces/IGatewaySenders.sol\";\nimport {IRequestManagerGatewayHandler} from \"src/common/interfaces/IGatewayHandlers.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {PricingLib} from \"src/common/libraries/PricingLib.sol\";\n\nimport {IPoolManager, VaultDetails} from \"src/vaults/interfaces/IPoolManager.sol\";\nimport {IBalanceSheet} from \"src/vaults/interfaces/IBalanceSheet.sol\";\nimport {IAsyncRequestManager, AsyncInvestmentState} from \"src/vaults/interfaces/investments/IAsyncRequestManager.sol\";\nimport {IAsyncRedeemManager} from \"src/vaults/interfaces/investments/IAsyncRedeemManager.sol\";\nimport {IAsyncDepositManager} from \"src/vaults/interfaces/investments/IAsyncDepositManager.sol\";\nimport {IDepositManager} from \"src/vaults/interfaces/investments/IDepositManager.sol\";\nimport {IRedeemManager} from \"src/vaults/interfaces/investments/IRedeemManager.sol\";\nimport {IBaseRequestManager} from \"src/vaults/interfaces/investments/IBaseRequestManager.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\nimport {IAsyncVault, IBaseVault, IAsyncRedeemVault, VaultKind} from \"src/vaults/interfaces/IBaseVaults.sol\";\nimport {BaseRequestManager} from \"src/vaults/BaseRequestManager.sol\";\nimport {IPoolEscrowProvider} from \"src/vaults/interfaces/factories/IPoolEscrowFactory.sol\";\nimport {IEscrow} from \"src/vaults/interfaces/IEscrow.sol\";\nimport {ESCROW_HOOK_ID} from \"src/common/interfaces/IHook.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\n\n/// @title Investment Manager\n/// @notice This is the main contract vaults interact with for\n/// both incoming and outgoing investment transactions.\ncontract AsyncRequestManager is BaseRequestManager, IAsyncRequestManager {\n using CastLib for *;\n using MessageLib for *;\n using BytesLib for bytes;\n using MathLib for uint256;\n\n IVaultMessageSender public sender;\n IBalanceSheet public balanceSheet;\n\n mapping(IBaseVault vault => mapping(address investor => AsyncInvestmentState)) public investments;\n\n constructor(IEscrow globalEscrow_, address root_, address deployer)\n BaseRequestManager(globalEscrow_, root_, deployer)\n {}\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n function file(bytes32 what, address data) external override(IBaseRequestManager, BaseRequestManager) auth {\n if (what == \"sender\") sender = IVaultMessageSender(data);\n else if (what == \"poolManager\") poolManager = IPoolManager(data);\n else if (what == \"balanceSheet\") balanceSheet = IBalanceSheet(data);\n else if (what == \"poolEscrowProvider\") poolEscrowProvider = IPoolEscrowProvider(data);\n else revert FileUnrecognizedParam();\n emit File(what, data);\n }\n\n //----------------------------------------------------------------------------------------------\n // Async investment handlers\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IAsyncDepositManager\n function requestDeposit(IBaseVault vault_, uint256 assets, address controller, address, address)\n public\n auth\n returns (bool)\n {\n uint128 assets_ = assets.toUint128();\n require(assets_ != 0, ZeroAmountNotAllowed());\n\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n PoolId poolId = vault_.poolId();\n ShareClassId scId = vault_.scId();\n\n require(poolManager.isLinked(poolId, scId, vaultDetails.asset, vault_), AssetNotAllowed());\n\n require(_canTransfer(vault_, address(0), controller, convertToShares(vault_, assets_)), TransferNotAllowed());\n\n AsyncInvestmentState storage state = investments[vault_][controller];\n require(state.pendingCancelDepositRequest != true, CancellationIsPending());\n\n state.pendingDepositRequest += assets_;\n sender.sendDepositRequest(poolId, scId, controller.toBytes32(), vaultDetails.assetId, assets_);\n\n return true;\n }\n\n /// @inheritdoc IAsyncRedeemManager\n function requestRedeem(IBaseVault vault_, uint256 shares, address controller, address owner, address)\n public\n auth\n returns (bool)\n {\n uint128 shares_ = shares.toUint128();\n require(shares_ != 0, ZeroAmountNotAllowed());\n\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n PoolId poolId = vault_.poolId();\n ShareClassId scId = vault_.scId();\n\n require(poolManager.isLinked(poolId, scId, vaultDetails.asset, vault_), AssetNotAllowed());\n\n require(\n _canTransfer(vault_, owner, ESCROW_HOOK_ID, shares)\n && _canTransfer(vault_, controller, ESCROW_HOOK_ID, shares),\n TransferNotAllowed()\n );\n\n AsyncInvestmentState storage state = investments[vault_][controller];\n require(state.pendingCancelRedeemRequest != true, CancellationIsPending());\n\n state.pendingRedeemRequest = state.pendingRedeemRequest + shares_;\n sender.sendRedeemRequest(poolId, scId, controller.toBytes32(), vaultDetails.assetId, shares_);\n\n return true;\n }\n\n /// @inheritdoc IAsyncDepositManager\n function cancelDepositRequest(IBaseVault vault_, address controller, address) public auth {\n AsyncInvestmentState storage state = investments[vault_][controller];\n require(state.pendingDepositRequest > 0, NoPendingRequest());\n require(state.pendingCancelDepositRequest != true, CancellationIsPending());\n state.pendingCancelDepositRequest = true;\n\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n\n sender.sendCancelDepositRequest(vault_.poolId(), vault_.scId(), controller.toBytes32(), vaultDetails.assetId);\n }\n\n /// @inheritdoc IAsyncRedeemManager\n function cancelRedeemRequest(IBaseVault vault_, address controller, address) public auth {\n uint256 approximateSharesPayout = pendingRedeemRequest(vault_, controller);\n require(approximateSharesPayout > 0, NoPendingRequest());\n require(_canTransfer(vault_, address(0), controller, approximateSharesPayout), TransferNotAllowed());\n\n AsyncInvestmentState storage state = investments[vault_][controller];\n require(state.pendingCancelRedeemRequest != true, CancellationIsPending());\n state.pendingCancelRedeemRequest = true;\n\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n\n sender.sendCancelRedeemRequest(vault_.poolId(), vault_.scId(), controller.toBytes32(), vaultDetails.assetId);\n }\n\n //----------------------------------------------------------------------------------------------\n // Gateway handlers\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IRequestManagerGatewayHandler\n function approvedDeposits(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n uint128 assetAmount,\n D18 pricePoolPerAsset\n ) external auth {\n (address asset, uint256 tokenId) = poolManager.idToAsset(assetId);\n\n // Note deposit and transfer from global escrow into the pool escrow,\n // to make assets available for managers of the balance sheet\n balanceSheet.overridePricePoolPerAsset(poolId, scId, assetId, pricePoolPerAsset);\n balanceSheet.noteDeposit(poolId, scId, asset, tokenId, address(globalEscrow), assetAmount);\n\n address poolEscrow = address(poolEscrowProvider.escrow(poolId));\n globalEscrow.authTransferTo(asset, tokenId, poolEscrow, assetAmount);\n }\n\n /// @inheritdoc IRequestManagerGatewayHandler\n function issuedShares(PoolId poolId, ShareClassId scId, uint128 shareAmount, D18 pricePoolPerShare) external auth {\n balanceSheet.overridePricePoolPerShare(poolId, scId, pricePoolPerShare);\n balanceSheet.issue(poolId, scId, address(globalEscrow), shareAmount);\n }\n\n /// @inheritdoc IRequestManagerGatewayHandler\n function revokedShares(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n uint128 assetAmount,\n uint128 shareAmount,\n D18 pricePoolPerShare\n ) external auth {\n // Lock assets to ensure they are not withdrawn and are available for the redeeming user\n (address asset, uint256 tokenId) = poolManager.idToAsset(assetId);\n poolEscrowProvider.escrow(poolId).reserveIncrease(scId, asset, tokenId, assetAmount);\n\n balanceSheet.overridePricePoolPerShare(poolId, scId, pricePoolPerShare);\n balanceSheet.revoke(poolId, scId, address(globalEscrow), shareAmount);\n }\n\n /// @inheritdoc IRequestManagerGatewayHandler\n function fulfillDepositRequest(\n PoolId poolId,\n ShareClassId scId,\n address user,\n AssetId assetId,\n uint128 assets,\n uint128 shares\n ) public auth {\n IAsyncVault vault_ = IAsyncVault(address(vault[poolId][scId][assetId]));\n\n AsyncInvestmentState storage state = investments[vault_][user];\n require(state.pendingDepositRequest != 0, NoPendingRequest());\n state.depositPrice = _calculatePriceAssetPerShare(\n vault_, state.maxMint + shares, _maxDeposit(vault_, user) + assets, MathLib.Rounding.Down\n );\n state.maxMint = state.maxMint + shares;\n state.pendingDepositRequest = state.pendingDepositRequest > assets ? state.pendingDepositRequest - assets : 0;\n\n if (state.pendingDepositRequest == 0) delete state.pendingCancelDepositRequest;\n\n vault_.onDepositClaimable(user, assets, shares);\n }\n\n /// @inheritdoc IRequestManagerGatewayHandler\n function fulfillRedeemRequest(\n PoolId poolId,\n ShareClassId scId,\n address user,\n AssetId assetId,\n uint128 assets,\n uint128 shares\n ) public auth {\n IAsyncRedeemVault vault_ = IAsyncRedeemVault(address(vault[poolId][scId][assetId]));\n\n AsyncInvestmentState storage state = investments[vault_][user];\n require(state.pendingRedeemRequest != 0, NoPendingRequest());\n\n // Calculate new weighted average redeem price and update order book values\n state.redeemPrice = _calculatePriceAssetPerShare(\n vault_, ((maxRedeem(vault_, user)) + shares).toUint128(), state.maxWithdraw + assets, MathLib.Rounding.Down\n );\n state.maxWithdraw = state.maxWithdraw + assets;\n state.pendingRedeemRequest = state.pendingRedeemRequest > shares ? state.pendingRedeemRequest - shares : 0;\n\n if (state.pendingRedeemRequest == 0) delete state.pendingCancelRedeemRequest;\n\n vault_.onRedeemClaimable(user, assets, shares);\n }\n\n /// @inheritdoc IRequestManagerGatewayHandler\n function fulfillCancelDepositRequest(\n PoolId poolId,\n ShareClassId scId,\n address user,\n AssetId assetId,\n uint128 assets,\n uint128 fulfillment\n ) public auth {\n IAsyncVault vault_ = IAsyncVault(address(vault[poolId][scId][assetId]));\n\n AsyncInvestmentState storage state = investments[vault_][user];\n require(state.pendingCancelDepositRequest == true, NoPendingRequest());\n\n state.claimableCancelDepositRequest = state.claimableCancelDepositRequest + assets;\n state.pendingDepositRequest =\n state.pendingDepositRequest > fulfillment ? state.pendingDepositRequest - fulfillment : 0;\n\n if (state.pendingDepositRequest == 0) delete state.pendingCancelDepositRequest;\n\n vault_.onCancelDepositClaimable(user, assets);\n }\n\n /// @inheritdoc IRequestManagerGatewayHandler\n function fulfillCancelRedeemRequest(PoolId poolId, ShareClassId scId, address user, AssetId assetId, uint128 shares)\n public\n auth\n {\n IAsyncRedeemVault vault_ = IAsyncRedeemVault(address(vault[poolId][scId][assetId]));\n AsyncInvestmentState storage state = investments[vault_][user];\n require(state.pendingCancelRedeemRequest == true, NoPendingRequest());\n\n state.claimableCancelRedeemRequest = state.claimableCancelRedeemRequest + shares;\n state.pendingRedeemRequest = state.pendingRedeemRequest > shares ? state.pendingRedeemRequest - shares : 0;\n\n if (state.pendingRedeemRequest == 0) delete state.pendingCancelRedeemRequest;\n\n vault_.onCancelRedeemClaimable(user, shares);\n }\n\n //----------------------------------------------------------------------------------------------\n // Sync investment handlers\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IDepositManager\n function deposit(IBaseVault vault_, uint256 assets, address receiver, address controller)\n public\n auth\n returns (uint256 shares)\n {\n require(assets <= _maxDeposit(vault_, controller), ExceedsMaxDeposit());\n\n AsyncInvestmentState storage state = investments[vault_][controller];\n\n uint128 sharesUp = _assetToShareAmount(vault_, assets.toUint128(), state.depositPrice, MathLib.Rounding.Up);\n uint128 sharesDown = _assetToShareAmount(vault_, assets.toUint128(), state.depositPrice, MathLib.Rounding.Down);\n shares = uint256(sharesDown);\n _processDeposit(state, sharesUp, sharesDown, vault_, receiver);\n }\n\n /// @inheritdoc IDepositManager\n function mint(IBaseVault vault_, uint256 shares, address receiver, address controller)\n public\n auth\n returns (uint256 assets)\n {\n AsyncInvestmentState storage state = investments[vault_][controller];\n uint128 shares_ = shares.toUint128();\n\n assets = uint256(_shareToAssetAmount(vault_, shares_, state.depositPrice, MathLib.Rounding.Up));\n _processDeposit(state, shares_, shares_, vault_, receiver);\n }\n\n function _processDeposit(\n AsyncInvestmentState storage state,\n uint128 sharesUp,\n uint128 sharesDown,\n IBaseVault vault_,\n address receiver\n ) internal {\n require(sharesUp <= state.maxMint, ExceedsDepositLimits());\n state.maxMint = state.maxMint > sharesUp ? state.maxMint - sharesUp : 0;\n\n if (sharesDown > 0) {\n globalEscrow.authTransferTo(vault_.share(), receiver, sharesDown);\n }\n }\n\n /// @inheritdoc IRedeemManager\n function redeem(IBaseVault vault_, uint256 shares, address receiver, address controller)\n public\n auth\n returns (uint256 assets)\n {\n require(shares <= maxRedeem(vault_, controller), ExceedsMaxRedeem());\n\n AsyncInvestmentState storage state = investments[vault_][controller];\n\n uint128 assetsUp = _shareToAssetAmount(vault_, shares.toUint128(), state.redeemPrice, MathLib.Rounding.Up);\n uint128 assetsDown = _shareToAssetAmount(vault_, shares.toUint128(), state.redeemPrice, MathLib.Rounding.Down);\n _processRedeem(state, assetsUp, assetsDown, vault_, receiver, controller);\n assets = uint256(assetsDown);\n }\n\n /// @inheritdoc IRedeemManager\n function withdraw(IBaseVault vault_, uint256 assets, address receiver, address controller)\n public\n auth\n returns (uint256 shares)\n {\n AsyncInvestmentState storage state = investments[vault_][controller];\n uint128 assets_ = assets.toUint128();\n _processRedeem(state, assets_, assets_, vault_, receiver, controller);\n\n shares = uint256(_assetToShareAmount(vault_, assets_, state.redeemPrice, MathLib.Rounding.Up));\n }\n\n function _processRedeem(\n AsyncInvestmentState storage state,\n uint128 assetsUp,\n uint128 assetsDown,\n IBaseVault vault_,\n address receiver,\n address controller\n ) internal {\n if (controller != receiver) {\n require(\n _canTransfer(vault_, controller, receiver, convertToShares(vault_, assetsDown)), TransferNotAllowed()\n );\n }\n\n require(_canTransfer(vault_, receiver, address(0), convertToShares(vault_, assetsDown)), TransferNotAllowed());\n\n require(assetsUp <= state.maxWithdraw, ExceedsRedeemLimits());\n state.maxWithdraw = state.maxWithdraw > assetsUp ? state.maxWithdraw - assetsUp : 0;\n\n if (assetsDown > 0) {\n _withdraw(vault_, receiver, assetsDown);\n }\n }\n\n /// @dev Transfer funds from escrow to receiver and update holdings\n function _withdraw(IBaseVault vault_, address receiver, uint128 assets) internal {\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n\n PoolId poolId = vault_.poolId();\n ShareClassId scId = vault_.scId();\n\n poolEscrowProvider.escrow(poolId).reserveDecrease(scId, vaultDetails.asset, vaultDetails.tokenId, assets);\n balanceSheet.withdraw(poolId, scId, vaultDetails.asset, vaultDetails.tokenId, receiver, assets);\n }\n\n //----------------------------------------------------------------------------------------------\n // Cancellation claim handlers\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IAsyncDepositManager\n function claimCancelDepositRequest(IBaseVault vault_, address receiver, address controller)\n public\n auth\n returns (uint256 assets)\n {\n AsyncInvestmentState storage state = investments[vault_][controller];\n assets = state.claimableCancelDepositRequest;\n state.claimableCancelDepositRequest = 0;\n uint256 shares = convertToShares(vault_, assets);\n\n if (controller != receiver) {\n require(_canTransfer(vault_, controller, receiver, shares), TransferNotAllowed());\n }\n require(_canTransfer(vault_, receiver, address(0), shares), TransferNotAllowed());\n\n if (assets > 0) {\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n globalEscrow.authTransferTo(vaultDetails.asset, vaultDetails.tokenId, receiver, assets);\n }\n }\n\n /// @inheritdoc IAsyncRedeemManager\n function claimCancelRedeemRequest(IBaseVault vault_, address receiver, address controller)\n public\n auth\n returns (uint256 shares)\n {\n AsyncInvestmentState storage state = investments[vault_][controller];\n shares = state.claimableCancelRedeemRequest;\n state.claimableCancelRedeemRequest = 0;\n\n if (shares > 0) {\n globalEscrow.authTransferTo(vault_.share(), receiver, shares);\n }\n }\n\n //----------------------------------------------------------------------------------------------\n // View methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IDepositManager\n function maxDeposit(IBaseVault vault_, address user) public view returns (uint256 assets) {\n if (!_canTransfer(vault_, ESCROW_HOOK_ID, user, 0)) {\n return 0;\n }\n assets = uint256(_maxDeposit(vault_, user));\n }\n\n function _maxDeposit(IBaseVault vault_, address user) internal view returns (uint128 assets) {\n AsyncInvestmentState memory state = investments[vault_][user];\n\n assets = _shareToAssetAmount(vault_, state.maxMint, state.depositPrice, MathLib.Rounding.Down);\n }\n\n /// @inheritdoc IDepositManager\n function maxMint(IBaseVault vault_, address user) public view returns (uint256 shares) {\n if (!_canTransfer(vault_, ESCROW_HOOK_ID, user, 0)) {\n return 0;\n }\n shares = uint256(investments[vault_][user].maxMint);\n }\n\n /// @inheritdoc IRedeemManager\n function maxWithdraw(IBaseVault vault_, address user) public view returns (uint256 assets) {\n if (!_canTransfer(vault_, user, address(0), 0)) return 0;\n assets = uint256(investments[vault_][user].maxWithdraw);\n }\n\n /// @inheritdoc IRedeemManager\n function maxRedeem(IBaseVault vault_, address user) public view returns (uint256 shares) {\n if (!_canTransfer(vault_, user, address(0), 0)) return 0;\n AsyncInvestmentState memory state = investments[vault_][user];\n\n shares = uint256(_assetToShareAmount(vault_, state.maxWithdraw, state.redeemPrice, MathLib.Rounding.Down));\n }\n\n /// @inheritdoc IAsyncDepositManager\n function pendingDepositRequest(IBaseVault vault_, address user) public view returns (uint256 assets) {\n assets = uint256(investments[vault_][user].pendingDepositRequest);\n }\n\n /// @inheritdoc IAsyncRedeemManager\n function pendingRedeemRequest(IBaseVault vault_, address user) public view returns (uint256 shares) {\n shares = uint256(investments[vault_][user].pendingRedeemRequest);\n }\n\n /// @inheritdoc IAsyncDepositManager\n function pendingCancelDepositRequest(IBaseVault vault_, address user) public view returns (bool isPending) {\n isPending = investments[vault_][user].pendingCancelDepositRequest;\n }\n\n /// @inheritdoc IAsyncRedeemManager\n function pendingCancelRedeemRequest(IBaseVault vault_, address user) public view returns (bool isPending) {\n isPending = investments[vault_][user].pendingCancelRedeemRequest;\n }\n\n /// @inheritdoc IAsyncDepositManager\n function claimableCancelDepositRequest(IBaseVault vault_, address user) public view returns (uint256 assets) {\n assets = investments[vault_][user].claimableCancelDepositRequest;\n }\n\n /// @inheritdoc IAsyncRedeemManager\n function claimableCancelRedeemRequest(IBaseVault vault_, address user) public view returns (uint256 shares) {\n shares = investments[vault_][user].claimableCancelRedeemRequest;\n }\n\n //----------------------------------------------------------------------------------------------\n // Helpers\n //----------------------------------------------------------------------------------------------\n\n /// @dev Checks transfer restrictions for the vault shares. Sender (from) and receiver (to) have to both pass\n /// the restrictions for a successful share transfer.\n function _canTransfer(IBaseVault vault_, address from, address to, uint256 value) internal view returns (bool) {\n IShareToken share = IShareToken(vault_.share());\n return share.checkTransferRestriction(from, to, value);\n }\n\n function _assetToShareAmount(\n IBaseVault vault_,\n uint128 assets,\n uint256 priceAssetPerShare,\n MathLib.Rounding rounding\n ) internal view returns (uint128 shares) {\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n address shareToken = vault_.share();\n\n return PricingLib.assetToShareAmount(\n shareToken, vaultDetails.asset, vaultDetails.tokenId, assets, d18(priceAssetPerShare.toUint128()), rounding\n );\n }\n\n function _shareToAssetAmount(\n IBaseVault vault_,\n uint128 shares,\n uint256 priceAssetPerShare,\n MathLib.Rounding rounding\n ) internal view returns (uint128 assets) {\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n address shareToken = vault_.share();\n\n return PricingLib.shareToAssetAmount(\n shareToken, shares, vaultDetails.asset, vaultDetails.tokenId, d18(priceAssetPerShare.toUint128()), rounding\n );\n }\n\n function _calculatePriceAssetPerShare(IBaseVault vault_, uint128 shares, uint128 assets, MathLib.Rounding rounding)\n internal\n view\n returns (uint256 price)\n {\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n address shareToken = vault_.share();\n\n return PricingLib.calculatePriceAssetPerShare(\n shareToken, shares, vaultDetails.asset, vaultDetails.tokenId, assets, rounding\n );\n }\n}\n" + }, + "src/vaults/AsyncVault.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport \"src/misc/interfaces/IERC7540.sol\";\nimport \"src/misc/interfaces/IERC7575.sol\";\nimport {SafeTransferLib} from \"src/misc/libraries/SafeTransferLib.sol\";\nimport {IERC20} from \"src/misc/interfaces/IERC20.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nimport {IAsyncRedeemVault, VaultKind} from \"src/vaults/interfaces/IBaseVaults.sol\";\nimport {BaseVault, BaseAsyncRedeemVault} from \"src/vaults/BaseVaults.sol\";\nimport {IAsyncVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\nimport {IAsyncRequestManager} from \"src/vaults/interfaces/investments/IAsyncRequestManager.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\n\n/// @title AsyncVault\n/// @notice Asynchronous Tokenized Vault standard implementation for Centrifuge pools\n///\n/// @dev Each vault issues shares of Centrifuge share class tokens as restricted ERC-20 tokens\n/// against asset deposits based on the current share price.\n///\n/// ERC-7540 is an extension of the ERC-4626 standard by 'requestDeposit' & 'requestRedeem' methods, where\n/// deposit and redeem orders are submitted to the pools to be included in the execution of the following epoch.\n/// After execution users can use the deposit, mint, redeem and withdraw functions to get their shares\n/// and/or assets from the pools.\ncontract AsyncVault is BaseAsyncRedeemVault, IAsyncVault {\n constructor(\n PoolId poolId_,\n ShareClassId scId_,\n address asset_,\n IShareToken token_,\n address root_,\n IAsyncRequestManager manager_\n ) BaseVault(poolId_, scId_, asset_, token_, root_, manager_) BaseAsyncRedeemVault(manager_) {}\n\n //----------------------------------------------------------------------------------------------\n // ERC-7540 deposit\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC7540Deposit\n function requestDeposit(uint256 assets, address controller, address owner) public returns (uint256) {\n require(owner == msg.sender || isOperator[owner][msg.sender], InvalidOwner());\n require(IERC20(asset).balanceOf(owner) >= assets, InsufficientBalance());\n\n require(asyncManager().requestDeposit(this, assets, controller, owner, msg.sender), RequestDepositFailed());\n SafeTransferLib.safeTransferFrom(asset, owner, address(manager.globalEscrow()), assets);\n\n emit DepositRequest(controller, owner, REQUEST_ID, msg.sender, assets);\n return REQUEST_ID;\n }\n\n /// @inheritdoc IERC7540Deposit\n function pendingDepositRequest(uint256, address controller) public view returns (uint256 pendingAssets) {\n pendingAssets = asyncManager().pendingDepositRequest(this, controller);\n }\n\n /// @inheritdoc IERC7540Deposit\n function claimableDepositRequest(uint256, address controller) external view returns (uint256 claimableAssets) {\n claimableAssets = maxDeposit(controller);\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-7887\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC7887Deposit\n function cancelDepositRequest(uint256, address controller) external {\n _validateController(controller);\n asyncManager().cancelDepositRequest(this, controller, msg.sender);\n emit CancelDepositRequest(controller, REQUEST_ID, msg.sender);\n }\n\n /// @inheritdoc IERC7887Deposit\n function pendingCancelDepositRequest(uint256, address controller) public view returns (bool isPending) {\n isPending = asyncManager().pendingCancelDepositRequest(this, controller);\n }\n\n /// @inheritdoc IERC7887Deposit\n function claimableCancelDepositRequest(uint256, address controller) public view returns (uint256 claimableAssets) {\n claimableAssets = asyncManager().claimableCancelDepositRequest(this, controller);\n }\n\n /// @inheritdoc IERC7887Deposit\n function claimCancelDepositRequest(uint256, address receiver, address controller)\n external\n returns (uint256 assets)\n {\n _validateController(controller);\n assets = asyncManager().claimCancelDepositRequest(this, receiver, controller);\n emit CancelDepositClaim(controller, receiver, REQUEST_ID, msg.sender, assets);\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-165\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC165\n function supportsInterface(bytes4 interfaceId) public pure override(BaseAsyncRedeemVault, IERC165) returns (bool) {\n return interfaceId == type(IERC7540Deposit).interfaceId || interfaceId == type(IERC7887Deposit).interfaceId\n || super.supportsInterface(interfaceId);\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-7540 claim\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC7575\n function maxDeposit(address controller) public view returns (uint256 maxAssets) {\n maxAssets = asyncManager().maxDeposit(this, controller);\n }\n\n /// @inheritdoc IERC7540Deposit\n function deposit(uint256 assets, address receiver, address controller) public returns (uint256 shares) {\n _validateController(controller);\n shares = asyncManager().deposit(this, assets, receiver, controller);\n emit Deposit(controller, receiver, assets, shares);\n }\n\n /// @inheritdoc IERC7575\n /// @notice When claiming deposit requests using deposit(), there can be some precision loss leading to dust.\n /// It is recommended to use mint() to claim deposit requests instead.\n function deposit(uint256 assets, address receiver) external returns (uint256 shares) {\n shares = deposit(assets, receiver, msg.sender);\n }\n\n /// @inheritdoc IERC7575\n function maxMint(address controller) public view returns (uint256 maxShares) {\n maxShares = asyncManager().maxMint(this, controller);\n }\n\n /// @inheritdoc IERC7540Deposit\n function mint(uint256 shares, address receiver, address controller) public returns (uint256 assets) {\n _validateController(controller);\n assets = asyncManager().mint(this, shares, receiver, controller);\n emit Deposit(controller, receiver, assets, shares);\n }\n\n /// @inheritdoc IERC7575\n function mint(uint256 shares, address receiver) public returns (uint256 assets) {\n assets = mint(shares, receiver, msg.sender);\n }\n\n /// @dev Strongly-typed accessor to the generic async redeem manager\n function asyncManager() public view returns (IAsyncRequestManager) {\n return IAsyncRequestManager(address(IAsyncRedeemVault(this).asyncRedeemManager()));\n }\n\n /// @dev Preview functions for ERC-7540 vaults revert\n function previewDeposit(uint256) external pure returns (uint256) {\n revert();\n }\n\n /// @dev Preview functions for ERC-7540 vaults revert\n function previewMint(uint256) external pure returns (uint256) {\n revert();\n }\n\n //----------------------------------------------------------------------------------------------\n // Event emitters\n //----------------------------------------------------------------------------------------------\n\n function onDepositClaimable(address controller, uint256 assets, uint256 shares) public virtual auth {\n emit DepositClaimable(controller, REQUEST_ID, assets, shares);\n }\n\n function onCancelDepositClaimable(address controller, uint256 assets) public virtual auth {\n emit CancelDepositClaimable(controller, REQUEST_ID, assets);\n }\n\n //----------------------------------------------------------------------------------------------\n // IBaseVault view\n //----------------------------------------------------------------------------------------------\n\n function vaultKind() public pure returns (VaultKind vaultKind_) {\n return VaultKind.Async;\n }\n}\n" + }, + "src/vaults/BalanceSheet.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {IAuth} from \"src/misc/interfaces/IAuth.sol\";\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {D18, d18} from \"src/misc/types/D18.sol\";\nimport {IERC6909} from \"src/misc/interfaces/IERC6909.sol\";\nimport {Recoverable} from \"src/misc/Recoverable.sol\";\nimport {SafeTransferLib} from \"src/misc/libraries/SafeTransferLib.sol\";\nimport {TransientStorageLib} from \"src/misc/libraries/TransientStorageLib.sol\";\n\nimport {IRoot} from \"src/common/interfaces/IRoot.sol\";\nimport {IGateway} from \"src/common/interfaces/IGateway.sol\";\nimport {MessageLib, UpdateContractType} from \"src/common/libraries/MessageLib.sol\";\nimport {IVaultMessageSender} from \"../common/interfaces/IGatewaySenders.sol\";\nimport {IBalanceSheetGatewayHandler} from \"src/common/interfaces/IGatewayHandlers.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\n\nimport {IPoolManager} from \"src/vaults/interfaces/IPoolManager.sol\";\nimport {IBalanceSheet, QueueAmount} from \"src/vaults/interfaces/IBalanceSheet.sol\";\nimport {IPoolEscrow} from \"src/vaults/interfaces/IEscrow.sol\";\nimport {IUpdateContract} from \"src/vaults/interfaces/IUpdateContract.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\nimport {IPoolEscrowProvider} from \"src/vaults/interfaces/factories/IPoolEscrowFactory.sol\";\n\n/// @title Balance Sheet\n/// @notice Management contract that integrates all balance sheet functions of a pool:\n/// - Issuing and revoking shares\n/// - Depositing and withdrawing assets\n/// - Force transferring shares\n///\n/// Share and asset updates to the Hub are optionally queued, to reduce the cost\n/// per transaction. Dequeuing can be triggered locally by the manager or from the Hub.\ncontract BalanceSheet is Auth, Recoverable, IBalanceSheet, IBalanceSheetGatewayHandler, IUpdateContract {\n using MathLib for *;\n using CastLib for bytes32;\n\n IRoot public immutable root;\n\n IPoolManager public poolManager;\n IVaultMessageSender public sender;\n IPoolEscrowProvider public poolEscrowProvider;\n\n mapping(PoolId => mapping(address => bool)) public manager;\n mapping(PoolId poolId => mapping(ShareClassId scId => bool)) public queueEnabled;\n mapping(PoolId poolId => mapping(ShareClassId scId => QueueAmount)) public queuedShares;\n mapping(PoolId poolId => mapping(ShareClassId scId => mapping(AssetId assetId => QueueAmount))) public queuedAssets;\n\n constructor(IRoot root_, address deployer) Auth(deployer) {\n root = root_;\n }\n\n /// @dev Check if the msg.sender is ward or a manager\n modifier authOrManager(PoolId poolId) {\n require(wards[msg.sender] == 1 || manager[poolId][msg.sender], IAuth.NotAuthorized());\n _;\n }\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n function file(bytes32 what, address data) external auth {\n if (what == \"poolManager\") poolManager = IPoolManager(data);\n else if (what == \"sender\") sender = IVaultMessageSender(data);\n else if (what == \"poolEscrowProvider\") poolEscrowProvider = IPoolEscrowProvider(data);\n else revert FileUnrecognizedParam();\n emit File(what, data);\n }\n\n function update(PoolId poolId, ShareClassId, /* scId */ bytes calldata payload) external auth {\n uint8 kind = uint8(MessageLib.updateContractType(payload));\n\n if (kind == uint8(UpdateContractType.UpdateManager)) {\n MessageLib.UpdateContractUpdateManager memory m = MessageLib.deserializeUpdateContractUpdateManager(payload);\n address who = m.who.toAddress();\n\n manager[poolId][who] = m.canManage;\n emit UpdateManager(poolId, who, m.canManage);\n } else {\n revert UnknownUpdateContractType();\n }\n }\n\n //----------------------------------------------------------------------------------------------\n // Management functions\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IBalanceSheet\n function deposit(PoolId poolId, ShareClassId scId, address asset, uint256 tokenId, address owner, uint128 amount)\n external\n authOrManager(poolId)\n {\n AssetId assetId = poolManager.assetToId(asset, tokenId);\n _noteDeposit(poolId, scId, assetId, asset, tokenId, owner, amount);\n _executeDeposit(poolId, asset, tokenId, owner, amount);\n }\n\n /// @inheritdoc IBalanceSheet\n /// @dev This function is mostly useful to keep higher level integrations CEI adherent.\n function noteDeposit(\n PoolId poolId,\n ShareClassId scId,\n address asset,\n uint256 tokenId,\n address owner,\n uint128 amount\n ) external authOrManager(poolId) {\n AssetId assetId = poolManager.assetToId(asset, tokenId);\n _noteDeposit(poolId, scId, assetId, asset, tokenId, owner, amount);\n }\n\n /// @inheritdoc IBalanceSheet\n function withdraw(\n PoolId poolId,\n ShareClassId scId,\n address asset,\n uint256 tokenId,\n address receiver,\n uint128 amount\n ) external authOrManager(poolId) {\n AssetId assetId = poolManager.assetToId(asset, tokenId);\n _withdraw(poolId, scId, assetId, asset, tokenId, receiver, amount);\n }\n\n /// @inheritdoc IBalanceSheet\n function issue(PoolId poolId, ShareClassId scId, address to, uint128 shares) external authOrManager(poolId) {\n _issue(poolId, scId, to, shares);\n }\n\n /// @inheritdoc IBalanceSheet\n function revoke(PoolId poolId, ShareClassId scId, address from, uint128 shares) external authOrManager(poolId) {\n _noteRevoke(poolId, scId, from, shares);\n _executeRevoke(poolId, scId, from, shares);\n }\n\n /// @inheritdoc IBalanceSheet\n /// @dev This function is mostly useful to keep higher level integrations CEI adherent.\n function noteRevoke(PoolId poolId, ShareClassId scId, address from, uint128 shares)\n external\n authOrManager(poolId)\n {\n _noteRevoke(poolId, scId, from, shares);\n }\n\n /// @inheritdoc IBalanceSheet\n function transferSharesFrom(PoolId poolId, ShareClassId scId, address from, address to, uint256 amount)\n external\n authOrManager(poolId)\n {\n require(!root.endorsed(from), CannotTransferFromEndorsedContract());\n IShareToken token = IShareToken(poolManager.shareToken(poolId, scId));\n token.authTransferFrom(from, from, to, amount);\n }\n\n /// @inheritdoc IBalanceSheet\n function overridePricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId, D18 value)\n external\n authOrManager(poolId)\n {\n TransientStorageLib.tstore(keccak256(abi.encode(\"pricePoolPerAsset\", poolId, scId, assetId)), value.raw());\n TransientStorageLib.tstore(keccak256(abi.encode(\"pricePoolPerAssetIsSet\", poolId, scId, assetId)), true);\n }\n\n /// @inheritdoc IBalanceSheet\n function overridePricePoolPerShare(PoolId poolId, ShareClassId scId, D18 value) external authOrManager(poolId) {\n TransientStorageLib.tstore(keccak256(abi.encode(\"pricePoolPerShare\", poolId, scId)), value.raw());\n TransientStorageLib.tstore(keccak256(abi.encode(\"pricePoolPerShareIsSet\", poolId, scId)), true);\n }\n\n //----------------------------------------------------------------------------------------------\n // Gateway handlers\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IBalanceSheetGatewayHandler\n function triggerDeposit(PoolId poolId, ShareClassId scId, AssetId assetId, address owner, uint128 amount)\n external\n auth\n {\n (address asset, uint256 tokenId) = poolManager.idToAsset(assetId);\n _noteDeposit(poolId, scId, assetId, asset, tokenId, owner, amount);\n _executeDeposit(poolId, asset, tokenId, owner, amount);\n }\n\n /// @inheritdoc IBalanceSheetGatewayHandler\n function triggerWithdraw(PoolId poolId, ShareClassId scId, AssetId assetId, address receiver, uint128 amount)\n external\n auth\n {\n (address asset, uint256 tokenId) = poolManager.idToAsset(assetId);\n _withdraw(poolId, scId, assetId, asset, tokenId, receiver, amount);\n }\n\n /// @inheritdoc IBalanceSheetGatewayHandler\n function triggerIssueShares(PoolId poolId, ShareClassId scId, address receiver, uint128 shares) external auth {\n _issue(poolId, scId, receiver, shares);\n }\n\n /// @inheritdoc IBalanceSheetGatewayHandler\n function setQueue(PoolId poolId, ShareClassId scId, bool enabled) external auth {\n queueEnabled[poolId][scId] = enabled;\n }\n\n /// @inheritdoc IBalanceSheetGatewayHandler\n function submitQueuedAssets(PoolId poolId, ShareClassId scId, AssetId assetId) external authOrManager(poolId) {\n _submitQueuedAssets(poolId, scId, assetId);\n }\n\n /// @inheritdoc IBalanceSheetGatewayHandler\n function submitQueuedShares(PoolId poolId, ShareClassId scId) external authOrManager(poolId) {\n _submitQueuedShares(poolId, scId);\n }\n\n //----------------------------------------------------------------------------------------------\n // Internal\n //----------------------------------------------------------------------------------------------\n\n function _noteDeposit(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n address asset,\n uint256 tokenId,\n address owner,\n uint128 amount\n ) internal {\n IPoolEscrow escrow = poolEscrowProvider.escrow(poolId);\n escrow.deposit(scId, asset, tokenId, amount);\n\n D18 pricePoolPerAsset_ = _pricePoolPerAsset(poolId, scId, assetId);\n emit Deposit(poolId, scId, asset, tokenId, owner, amount, pricePoolPerAsset_);\n\n if (queueEnabled[poolId][scId]) {\n queuedAssets[poolId][scId][assetId].increase += amount;\n } else {\n sender.sendUpdateHoldingAmount(poolId, scId, assetId, owner, amount, pricePoolPerAsset_, true);\n }\n }\n\n function _executeDeposit(PoolId poolId, address asset, uint256 tokenId, address owner, uint128 amount) internal {\n IPoolEscrow escrow = poolEscrowProvider.escrow(poolId);\n if (tokenId == 0) {\n SafeTransferLib.safeTransferFrom(asset, owner, address(escrow), amount);\n } else {\n IERC6909(asset).transferFrom(owner, address(escrow), tokenId, amount);\n }\n }\n\n function _withdraw(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n address asset,\n uint256 tokenId,\n address receiver,\n uint128 amount\n ) internal {\n IPoolEscrow escrow = poolEscrowProvider.escrow(poolId);\n escrow.withdraw(scId, asset, tokenId, amount);\n\n D18 pricePoolPerAsset_ = _pricePoolPerAsset(poolId, scId, assetId);\n emit Withdraw(poolId, scId, asset, tokenId, receiver, amount, pricePoolPerAsset_);\n\n if (queueEnabled[poolId][scId]) {\n queuedAssets[poolId][scId][assetId].decrease += amount;\n } else {\n sender.sendUpdateHoldingAmount(poolId, scId, assetId, receiver, amount, pricePoolPerAsset_, false);\n }\n\n escrow.authTransferTo(asset, tokenId, receiver, amount);\n }\n\n function _issue(PoolId poolId, ShareClassId scId, address to, uint128 shares) internal {\n emit Issue(poolId, scId, to, _pricePoolPerShare(poolId, scId), shares);\n\n if (queueEnabled[poolId][scId]) {\n queuedShares[poolId][scId].increase += shares;\n } else {\n sender.sendUpdateShares(poolId, scId, shares, true);\n }\n\n IShareToken token = poolManager.shareToken(poolId, scId);\n token.mint(to, shares);\n }\n\n function _noteRevoke(PoolId poolId, ShareClassId scId, address from, uint128 shares) internal {\n emit Revoke(poolId, scId, from, _pricePoolPerShare(poolId, scId), shares);\n\n if (queueEnabled[poolId][scId]) {\n queuedShares[poolId][scId].decrease += shares;\n } else {\n sender.sendUpdateShares(poolId, scId, shares, false);\n }\n }\n\n function _executeRevoke(PoolId poolId, ShareClassId scId, address from, uint128 shares) internal {\n IShareToken token = poolManager.shareToken(poolId, scId);\n token.authTransferFrom(from, from, address(this), shares);\n token.burn(address(this), shares);\n }\n\n function _submitQueuedShares(PoolId poolId, ShareClassId scId) internal {\n QueueAmount storage queue = queuedShares[poolId][scId];\n\n if (queue.increase > queue.decrease) {\n sender.sendUpdateShares(poolId, scId, queue.increase - queue.decrease, true);\n } else if (queue.decrease > queue.increase) {\n sender.sendUpdateShares(poolId, scId, queue.decrease - queue.increase, false);\n }\n\n queue.increase = 0;\n queue.decrease = 0;\n }\n\n function _submitQueuedAssets(PoolId poolId, ShareClassId scId, AssetId assetId) internal {\n QueueAmount storage queue = queuedAssets[poolId][scId][assetId];\n\n D18 pricePoolPerAsset = _pricePoolPerAsset(poolId, scId, assetId);\n if (queue.increase > queue.decrease) {\n sender.sendUpdateHoldingAmount(\n poolId, scId, assetId, address(0), queue.increase - queue.decrease, pricePoolPerAsset, true\n );\n } else if (queue.decrease > queue.increase) {\n sender.sendUpdateHoldingAmount(\n poolId, scId, assetId, address(0), queue.decrease - queue.increase, pricePoolPerAsset, false\n );\n }\n\n queue.increase = 0;\n queue.decrease = 0;\n }\n\n function _pricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId) internal view returns (D18) {\n if (TransientStorageLib.tloadBool(keccak256(abi.encode(\"pricePoolPerAssetIsSet\", poolId, scId, assetId)))) {\n return\n d18(TransientStorageLib.tloadUint128(keccak256(abi.encode(\"pricePoolPerAsset\", poolId, scId, assetId))));\n }\n\n D18 pricePoolPerAsset = poolManager.pricePoolPerAsset(poolId, scId, assetId, true);\n return pricePoolPerAsset;\n }\n\n function _pricePoolPerShare(PoolId poolId, ShareClassId scId) internal view returns (D18) {\n if (TransientStorageLib.tloadBool(keccak256(abi.encode(\"pricePoolPerShareIsSet\", poolId, scId)))) {\n return d18(TransientStorageLib.tloadUint128(keccak256(abi.encode(\"pricePoolPerShare\", poolId, scId))));\n }\n\n D18 pricePoolPerShare = poolManager.pricePoolPerShare(poolId, scId, true);\n return pricePoolPerShare;\n }\n}\n" + }, + "src/vaults/BaseRequestManager.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {D18} from \"src/misc/types/D18.sol\";\nimport {Recoverable} from \"src/misc/Recoverable.sol\";\nimport {IAuth} from \"src/misc/interfaces/IAuth.sol\";\n\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {PricingLib} from \"src/common/libraries/PricingLib.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nimport {IPoolManager, VaultDetails} from \"src/vaults/interfaces/IPoolManager.sol\";\nimport {IBaseRequestManager} from \"src/vaults/interfaces/investments/IBaseRequestManager.sol\";\nimport {IPoolEscrowProvider} from \"src/vaults/interfaces/factories/IPoolEscrowFactory.sol\";\nimport {IBaseVault, VaultKind} from \"src/vaults/interfaces/IBaseVaults.sol\";\nimport {IPoolEscrow, IEscrow} from \"src/vaults/interfaces/IEscrow.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\n\nabstract contract BaseRequestManager is Auth, Recoverable, IBaseRequestManager {\n using MathLib for uint256;\n\n address public immutable root;\n IEscrow public immutable globalEscrow;\n\n IPoolManager public poolManager;\n IPoolEscrowProvider public poolEscrowProvider;\n\n mapping(PoolId poolId => mapping(ShareClassId scId => mapping(AssetId assetId => IBaseVault vault))) public vault;\n\n constructor(IEscrow globalEscrow_, address root_, address deployer) Auth(deployer) {\n globalEscrow = globalEscrow_;\n root = root_;\n }\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IBaseRequestManager\n function file(bytes32 what, address data) external virtual auth {\n if (what == \"poolManager\") poolManager = IPoolManager(data);\n else if (what == \"poolEscrowProvider\") poolEscrowProvider = IPoolEscrowProvider(data);\n else revert FileUnrecognizedParam();\n emit File(what, data);\n }\n\n /// @inheritdoc IBaseRequestManager\n function addVault(PoolId poolId, ShareClassId scId, IBaseVault vault_, address asset_, AssetId assetId)\n public\n virtual\n auth\n {\n address token = vault_.share();\n\n require(vault_.asset() == asset_, AssetMismatch());\n require(address(vault[poolId][scId][assetId]) == address(0), VaultAlreadyExists());\n\n vault[poolId][scId][assetId] = IBaseVault(address(vault_));\n IAuth(token).rely(address(vault_));\n IShareToken(token).updateVault(vault_.asset(), address(vault_));\n rely(address(vault_));\n }\n\n /// @inheritdoc IBaseRequestManager\n function removeVault(PoolId poolId, ShareClassId scId, IBaseVault vault_, address asset_, AssetId assetId)\n public\n virtual\n auth\n {\n address token = vault_.share();\n\n require(vault_.asset() == asset_, AssetMismatch());\n require(address(vault[poolId][scId][assetId]) != address(0), VaultDoesNotExist());\n\n delete vault[poolId][scId][assetId];\n\n IAuth(token).deny(address(vault_));\n IShareToken(token).updateVault(vault_.asset(), address(0));\n deny(address(vault_));\n }\n\n //----------------------------------------------------------------------------------------------\n // View methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IBaseRequestManager\n function convertToShares(IBaseVault vault_, uint256 assets) public view virtual returns (uint256 shares) {\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n (D18 pricePoolPerAsset, D18 pricePoolPerShare) =\n poolManager.pricesPoolPer(vault_.poolId(), vault_.scId(), vaultDetails.assetId, false);\n\n return _assetToShareAmount(\n vault_, vaultDetails, assets, pricePoolPerAsset, pricePoolPerShare, MathLib.Rounding.Down\n );\n }\n\n /// @inheritdoc IBaseRequestManager\n function convertToAssets(IBaseVault vault_, uint256 shares) public view virtual returns (uint256 assets) {\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n (D18 pricePoolPerAsset, D18 pricePoolPerShare) =\n poolManager.pricesPoolPer(vault_.poolId(), vault_.scId(), vaultDetails.assetId, false);\n\n return _shareToAssetAmount(\n vault_, vaultDetails, shares, pricePoolPerAsset, pricePoolPerShare, MathLib.Rounding.Down\n );\n }\n\n /// @inheritdoc IBaseRequestManager\n function priceLastUpdated(IBaseVault vault_) public view virtual returns (uint64 lastUpdated) {\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n\n (uint64 shareLastUpdated,,) = poolManager.markersPricePoolPerShare(vault_.poolId(), vault_.scId());\n (uint64 assetLastUpdated,,) =\n poolManager.markersPricePoolPerAsset(vault_.poolId(), vault_.scId(), vaultDetails.assetId);\n\n // Choose the latest update to be the marker\n lastUpdated = MathLib.max(shareLastUpdated, assetLastUpdated).toUint64();\n }\n\n /// @inheritdoc IBaseRequestManager\n function poolEscrow(PoolId poolId) public view returns (IPoolEscrow) {\n return poolEscrowProvider.escrow(poolId);\n }\n\n /// @inheritdoc IBaseRequestManager\n function vaultByAssetId(PoolId poolId, ShareClassId scId, AssetId assetId) public view returns (IBaseVault) {\n return vault[poolId][scId][assetId];\n }\n\n function _assetToShareAmount(\n IBaseVault vault_,\n VaultDetails memory vaultDetails,\n uint256 assets,\n D18 pricePoolPerAsset,\n D18 pricePoolPerShare,\n MathLib.Rounding rounding\n ) internal view returns (uint256 shares) {\n return PricingLib.assetToShareAmount(\n vault_.share(),\n vaultDetails.asset,\n vaultDetails.tokenId,\n assets.toUint128(),\n pricePoolPerAsset,\n pricePoolPerShare,\n rounding\n );\n }\n\n function _shareToAssetAmount(\n IBaseVault vault_,\n VaultDetails memory vaultDetails,\n uint256 shares,\n D18 pricePoolPerAsset,\n D18 pricePoolPerShare,\n MathLib.Rounding rounding\n ) internal view returns (uint256 assets) {\n return PricingLib.shareToAssetAmount(\n vault_.share(),\n shares.toUint128(),\n vaultDetails.asset,\n vaultDetails.tokenId,\n pricePoolPerAsset,\n pricePoolPerShare,\n rounding\n );\n }\n}\n" + }, + "src/vaults/BaseVaults.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport \"src/misc/interfaces/IERC7540.sol\";\nimport \"src/misc/interfaces/IERC7575.sol\";\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {IERC20Metadata} from \"src/misc/interfaces/IERC20.sol\";\nimport {EIP712Lib} from \"src/misc/libraries/EIP712Lib.sol\";\nimport {SignatureLib} from \"src/misc/libraries/SignatureLib.sol\";\nimport {SafeTransferLib} from \"src/misc/libraries/SafeTransferLib.sol\";\nimport {Recoverable} from \"src/misc/Recoverable.sol\";\n\nimport {IRoot} from \"src/common/interfaces/IRoot.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nimport {IBaseVault, IAsyncRedeemVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\nimport {IERC7575} from \"src/misc/interfaces/IERC7575.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\nimport {IAsyncRedeemManager} from \"src/vaults/interfaces/investments/IAsyncRedeemManager.sol\";\nimport {ISyncDepositManager} from \"src/vaults/interfaces/investments/ISyncDepositManager.sol\";\nimport {IBaseRequestManager} from \"src/vaults/interfaces/investments/IBaseRequestManager.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\n\nabstract contract BaseVault is Auth, Recoverable, IBaseVault {\n /// @dev Requests for Centrifuge pool are non-fungible and all have ID = 0\n uint256 internal constant REQUEST_ID = 0;\n\n IRoot public immutable root;\n /// @dev this naming MUST NEVER change - due to legacy v2 vaults\n IBaseRequestManager public manager;\n\n /// @inheritdoc IBaseVault\n PoolId public immutable poolId;\n /// @inheritdoc IBaseVault\n ShareClassId public immutable scId;\n\n /// @inheritdoc IERC7575\n address public immutable asset;\n\n /// @inheritdoc IERC7575\n address public immutable share;\n uint8 internal immutable _shareDecimals;\n\n /// --- ERC7741 ---\n bytes32 private immutable nameHash;\n bytes32 private immutable versionHash;\n uint256 public immutable deploymentChainId;\n bytes32 private immutable _DOMAIN_SEPARATOR;\n bytes32 public constant AUTHORIZE_OPERATOR_TYPEHASH =\n keccak256(\"AuthorizeOperator(address controller,address operator,bool approved,bytes32 nonce,uint256 deadline)\");\n\n /// @inheritdoc IERC7741\n mapping(address controller => mapping(bytes32 nonce => bool used)) public authorizations;\n\n /// @inheritdoc IERC7540Operator\n mapping(address => mapping(address => bool)) public isOperator;\n\n constructor(\n PoolId poolId_,\n ShareClassId scId_,\n address asset_,\n IShareToken token_,\n address root_,\n IBaseRequestManager manager_\n ) Auth(msg.sender) {\n poolId = poolId_;\n scId = scId_;\n asset = asset_;\n share = address(token_);\n _shareDecimals = IERC20Metadata(share).decimals();\n root = IRoot(root_);\n manager = IBaseRequestManager(manager_);\n\n nameHash = keccak256(bytes(\"Centrifuge\"));\n versionHash = keccak256(bytes(\"1\"));\n deploymentChainId = block.chainid;\n _DOMAIN_SEPARATOR = EIP712Lib.calculateDomainSeparator(nameHash, versionHash);\n }\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n function file(bytes32 what, address data) external virtual auth {\n if (what == \"manager\") manager = IBaseRequestManager(data);\n else revert FileUnrecognizedParam();\n emit File(what, data);\n }\n\n /// @inheritdoc IERC7540Operator\n function setOperator(address operator, bool approved) public virtual returns (bool success) {\n require(msg.sender != operator, CannotSetSelfAsOperator());\n isOperator[msg.sender][operator] = approved;\n emit OperatorSet(msg.sender, operator, approved);\n success = true;\n }\n\n /// @inheritdoc IBaseVault\n function setEndorsedOperator(address owner, bool approved) public virtual {\n require(msg.sender != owner, CannotSetSelfAsOperator());\n require(root.endorsed(msg.sender), NotEndorsed());\n isOperator[owner][msg.sender] = approved;\n emit OperatorSet(owner, msg.sender, approved);\n }\n\n /// @inheritdoc IERC7741\n function DOMAIN_SEPARATOR() public view returns (bytes32) {\n return block.chainid == deploymentChainId\n ? _DOMAIN_SEPARATOR\n : EIP712Lib.calculateDomainSeparator(nameHash, versionHash);\n }\n\n /// @inheritdoc IERC7741\n function authorizeOperator(\n address controller,\n address operator,\n bool approved,\n bytes32 nonce,\n uint256 deadline,\n bytes memory signature\n ) external returns (bool success) {\n require(controller != operator, CannotSetSelfAsOperator());\n require(block.timestamp <= deadline, ExpiredAuthorization());\n require(!authorizations[controller][nonce], AlreadyUsedAuthorization());\n\n authorizations[controller][nonce] = true;\n\n bytes32 digest = keccak256(\n abi.encodePacked(\n \"\\x19\\x01\",\n DOMAIN_SEPARATOR(),\n keccak256(abi.encode(AUTHORIZE_OPERATOR_TYPEHASH, controller, operator, approved, nonce, deadline))\n )\n );\n\n require(SignatureLib.isValidSignature(controller, digest, signature), InvalidAuthorization());\n\n isOperator[controller][operator] = approved;\n emit OperatorSet(controller, operator, approved);\n\n success = true;\n }\n\n /// @inheritdoc IERC7741\n function invalidateNonce(bytes32 nonce) external {\n authorizations[msg.sender][nonce] = true;\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-165\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC165\n function supportsInterface(bytes4 interfaceId) public pure virtual override returns (bool) {\n return interfaceId == type(IERC7540Operator).interfaceId || interfaceId == type(IERC7741).interfaceId\n || interfaceId == type(IERC7714).interfaceId || interfaceId == type(IERC7575).interfaceId\n || interfaceId == type(IERC165).interfaceId;\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-4626\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC7575\n function totalAssets() external view returns (uint256) {\n return convertToAssets(IERC20Metadata(share).totalSupply());\n }\n\n /// @inheritdoc IERC7575\n /// @notice The calculation is based on the token price from the most recent epoch retrieved from Centrifuge.\n /// The actual conversion MAY change between order submission and execution.\n function convertToShares(uint256 assets) public view returns (uint256 shares) {\n shares = manager.convertToShares(this, assets);\n }\n\n /// @inheritdoc IERC7575\n /// @notice The calculation is based on the token price from the most recent epoch retrieved from Centrifuge.\n /// The actual conversion MAY change between order submission and execution.\n function convertToAssets(uint256 shares) public view returns (uint256 assets) {\n assets = manager.convertToAssets(this, shares);\n }\n\n //----------------------------------------------------------------------------------------------\n // Helpers\n //----------------------------------------------------------------------------------------------\n\n /// @notice Price of 1 unit of share, quoted in the decimals of the asset.\n function pricePerShare() external view returns (uint256) {\n return convertToAssets(10 ** _shareDecimals);\n }\n\n /// @notice Returns timestamp of the last share price update.\n function priceLastUpdated() external view returns (uint64) {\n return manager.priceLastUpdated(this);\n }\n\n /// @inheritdoc IERC7714\n function isPermissioned(address controller) external view returns (bool) {\n return IShareToken(share).checkTransferRestriction(address(0), controller, 0);\n }\n\n /// @notice Ensures msg.sender can operate on behalf of controller.\n function _validateController(address controller) internal view {\n require(controller == msg.sender || isOperator[controller][msg.sender], InvalidController());\n }\n}\n\nabstract contract BaseAsyncRedeemVault is BaseVault, IAsyncRedeemVault {\n IAsyncRedeemManager public asyncRedeemManager;\n\n constructor(IAsyncRedeemManager asyncRequestManager_) {\n asyncRedeemManager = asyncRequestManager_;\n }\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n function file(bytes32 what, address data) external virtual override auth {\n if (what == \"manager\") manager = IBaseRequestManager(data);\n else if (what == \"asyncRedeemManager\") asyncRedeemManager = IAsyncRedeemManager(data);\n else revert FileUnrecognizedParam();\n emit File(what, data);\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-7540 redeem\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC7540Redeem\n function requestRedeem(uint256 shares, address controller, address owner) public returns (uint256) {\n require(IShareToken(share).balanceOf(owner) >= shares, InsufficientBalance());\n\n // If msg.sender is operator of owner, the transfer is executed as if\n // the sender is the owner, to bypass the allowance check\n address sender = isOperator[owner][msg.sender] ? owner : msg.sender;\n\n require(asyncRedeemManager.requestRedeem(this, shares, controller, owner, sender), RequestRedeemFailed());\n IShareToken(share).authTransferFrom(sender, owner, address(manager.globalEscrow()), shares);\n\n emit RedeemRequest(controller, owner, REQUEST_ID, msg.sender, shares);\n return REQUEST_ID;\n }\n\n /// @inheritdoc IERC7540Redeem\n function pendingRedeemRequest(uint256, address controller) public view returns (uint256 pendingShares) {\n pendingShares = asyncRedeemManager.pendingRedeemRequest(this, controller);\n }\n\n /// @inheritdoc IERC7540Redeem\n function claimableRedeemRequest(uint256, address controller) external view returns (uint256 claimableShares) {\n claimableShares = maxRedeem(controller);\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-7887\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC7887Redeem\n function cancelRedeemRequest(uint256, address controller) external {\n _validateController(controller);\n asyncRedeemManager.cancelRedeemRequest(this, controller, msg.sender);\n emit CancelRedeemRequest(controller, REQUEST_ID, msg.sender);\n }\n\n /// @inheritdoc IERC7887Redeem\n function pendingCancelRedeemRequest(uint256, address controller) public view returns (bool isPending) {\n isPending = asyncRedeemManager.pendingCancelRedeemRequest(this, controller);\n }\n\n /// @inheritdoc IERC7887Redeem\n function claimableCancelRedeemRequest(uint256, address controller) public view returns (uint256 claimableShares) {\n claimableShares = asyncRedeemManager.claimableCancelRedeemRequest(this, controller);\n }\n\n /// @inheritdoc IERC7887Redeem\n function claimCancelRedeemRequest(uint256, address receiver, address controller)\n external\n returns (uint256 shares)\n {\n _validateController(controller);\n shares = asyncRedeemManager.claimCancelRedeemRequest(this, receiver, controller);\n emit CancelRedeemClaim(receiver, controller, REQUEST_ID, msg.sender, shares);\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-7540 claim\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC7575\n /// @notice DOES NOT support controller != msg.sender since shares are already transferred on requestRedeem\n function withdraw(uint256 assets, address receiver, address controller) public returns (uint256 shares) {\n _validateController(controller);\n shares = asyncRedeemManager.withdraw(this, assets, receiver, controller);\n emit Withdraw(msg.sender, receiver, controller, assets, shares);\n }\n\n /// @inheritdoc IERC7575\n /// @notice DOES NOT support controller != msg.sender since shares are already transferred on requestRedeem.\n /// When claiming redemption requests using redeem(), there can be some precision loss leading to dust.\n /// It is recommended to use withdraw() to claim redemption requests instead.\n function redeem(uint256 shares, address receiver, address controller) external returns (uint256 assets) {\n _validateController(controller);\n assets = asyncRedeemManager.redeem(this, shares, receiver, controller);\n emit Withdraw(msg.sender, receiver, controller, assets, shares);\n }\n\n //----------------------------------------------------------------------------------------------\n // Event emitters\n //----------------------------------------------------------------------------------------------\n\n function onRedeemRequest(address controller, address owner, uint256 shares) public virtual auth {\n emit RedeemRequest(controller, owner, REQUEST_ID, msg.sender, shares);\n }\n\n function onRedeemClaimable(address controller, uint256 assets, uint256 shares) public virtual auth {\n emit RedeemClaimable(controller, REQUEST_ID, assets, shares);\n }\n\n function onCancelRedeemClaimable(address controller, uint256 shares) public virtual auth {\n emit CancelRedeemClaimable(controller, REQUEST_ID, shares);\n }\n\n //----------------------------------------------------------------------------------------------\n // View methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC165\n function supportsInterface(bytes4 interfaceId) public pure virtual override(BaseVault, IERC165) returns (bool) {\n return super.supportsInterface(interfaceId) || interfaceId == type(IERC7540Redeem).interfaceId\n || interfaceId == type(IERC7887Redeem).interfaceId;\n }\n\n /// @inheritdoc IERC7575\n function maxWithdraw(address controller) public view returns (uint256 maxAssets) {\n maxAssets = asyncRedeemManager.maxWithdraw(this, controller);\n }\n\n /// @inheritdoc IERC7575\n function maxRedeem(address controller) public view returns (uint256 maxShares) {\n maxShares = asyncRedeemManager.maxRedeem(this, controller);\n }\n\n /// @dev Preview functions for ERC-7540 vaults revert\n function previewWithdraw(uint256) external pure returns (uint256) {\n revert();\n }\n\n /// @dev Preview functions for ERC-7540 vaults revert\n function previewRedeem(uint256) external pure returns (uint256) {\n revert();\n }\n}\n\nabstract contract BaseSyncDepositVault is BaseVault {\n ISyncDepositManager public syncDepositManager;\n\n constructor(ISyncDepositManager syncRequestManager_) {\n syncDepositManager = syncRequestManager_;\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-4626\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC7575\n function maxDeposit(address owner) public view returns (uint256 maxAssets) {\n maxAssets = syncDepositManager.maxDeposit(this, owner);\n }\n\n /// @inheritdoc IERC7575\n function previewDeposit(uint256 assets) external view override returns (uint256 shares) {\n shares = syncDepositManager.previewDeposit(this, msg.sender, assets);\n }\n\n /// @inheritdoc IERC7575\n function deposit(uint256 assets, address receiver) external returns (uint256 shares) {\n shares = syncDepositManager.deposit(this, assets, receiver, msg.sender);\n // NOTE: For security reasons, transfer must stay at end of call despite the fact that it logically should\n // happen before depositing in the manager\n SafeTransferLib.safeTransferFrom(asset, msg.sender, address(manager.poolEscrow(poolId)), assets);\n emit Deposit(receiver, msg.sender, assets, shares);\n }\n\n /// @inheritdoc IERC7575\n function maxMint(address owner) public view returns (uint256 maxShares) {\n maxShares = syncDepositManager.maxMint(this, owner);\n }\n\n /// @inheritdoc IERC7575\n function previewMint(uint256 shares) external view returns (uint256 assets) {\n assets = syncDepositManager.previewMint(this, msg.sender, shares);\n }\n\n /// @inheritdoc IERC7575\n function mint(uint256 shares, address receiver) public returns (uint256 assets) {\n assets = syncDepositManager.mint(this, shares, receiver, msg.sender);\n // NOTE: For security reasons, transfer must stay at end of call\n SafeTransferLib.safeTransferFrom(asset, msg.sender, address(manager.poolEscrow(poolId)), assets);\n emit Deposit(receiver, msg.sender, assets, shares);\n }\n\n /// @inheritdoc IERC165\n function supportsInterface(bytes4 interfaceId) public pure virtual override(BaseVault) returns (bool) {\n return super.supportsInterface(interfaceId);\n }\n}\n" + }, + "src/vaults/Escrow.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {IERC20} from \"src/misc/interfaces/IERC20.sol\";\nimport {IERC6909} from \"src/misc/interfaces/IERC6909.sol\";\nimport {SafeTransferLib} from \"src/misc/libraries/SafeTransferLib.sol\";\nimport {Recoverable} from \"src/misc/Recoverable.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {Holding, IPoolEscrow, IEscrow} from \"src/vaults/interfaces/IEscrow.sol\";\n\ncontract Escrow is Auth, IEscrow {\n constructor(address deployer) Auth(deployer) {}\n\n /// @inheritdoc IEscrow\n function authTransferTo(address asset, uint256 tokenId, address receiver, uint256 amount) public auth {\n if (tokenId == 0) {\n uint256 balance = IERC20(asset).balanceOf(address(this));\n require(balance >= amount, InsufficientBalance(asset, tokenId, amount, balance));\n\n SafeTransferLib.safeTransfer(asset, receiver, amount);\n } else {\n uint256 balance = IERC6909(asset).balanceOf(address(this), tokenId);\n require(balance >= amount, InsufficientBalance(asset, tokenId, amount, balance));\n\n IERC6909(asset).transfer(receiver, tokenId, amount);\n }\n\n emit AuthTransferTo(asset, tokenId, receiver, amount);\n }\n\n /// @inheritdoc IEscrow\n function authTransferTo(address asset, address receiver, uint256 amount) external auth {\n authTransferTo(asset, 0, receiver, amount);\n }\n}\n\n/// @title Escrow\n/// @notice Escrow contract that holds assets for a specific pool separated by share classes.\n/// Only wards can approve funds to be taken out.\ncontract PoolEscrow is Escrow, Recoverable, IPoolEscrow {\n /// @dev The underlying pool id\n PoolId public immutable poolId;\n\n mapping(ShareClassId scId => mapping(address asset => mapping(uint256 tokenId => Holding))) public holding;\n\n constructor(PoolId poolId_, address deployer) Escrow(deployer) {\n poolId = poolId_;\n }\n\n receive() external payable {}\n\n /// @inheritdoc IPoolEscrow\n function deposit(ShareClassId scId, address asset, uint256 tokenId, uint128 value) external auth {\n holding[scId][asset][tokenId].total += value;\n\n emit Deposit(asset, tokenId, poolId, scId, value);\n }\n\n /// @inheritdoc IPoolEscrow\n function withdraw(ShareClassId scId, address asset, uint256 tokenId, uint128 value) external auth {\n Holding storage holding_ = holding[scId][asset][tokenId];\n uint128 balance = holding_.total - holding_.reserved;\n require(balance >= value, InsufficientBalance(asset, tokenId, value, balance));\n\n holding_.total -= value;\n\n emit Withdraw(asset, tokenId, poolId, scId, value);\n }\n\n /// @inheritdoc IPoolEscrow\n function reserveIncrease(ShareClassId scId, address asset, uint256 tokenId, uint128 value) external auth {\n uint128 newValue = holding[scId][asset][tokenId].reserved + value;\n holding[scId][asset][tokenId].reserved = newValue;\n\n emit IncreaseReserve(asset, tokenId, poolId, scId, value, newValue);\n }\n\n /// @inheritdoc IPoolEscrow\n function reserveDecrease(ShareClassId scId, address asset, uint256 tokenId, uint128 value) external auth {\n uint128 prevValue = holding[scId][asset][tokenId].reserved;\n uint128 value_ = value;\n require(prevValue >= value_, InsufficientReservedAmount());\n\n uint128 newValue = prevValue - value_;\n holding[scId][asset][tokenId].reserved = newValue;\n\n emit DecreaseReserve(asset, tokenId, poolId, scId, value, newValue);\n }\n\n /// @inheritdoc IPoolEscrow\n function availableBalanceOf(ShareClassId scId, address asset, uint256 tokenId) public view returns (uint128) {\n Holding storage holding_ = holding[scId][asset][tokenId];\n if (holding_.total < holding_.reserved) return 0;\n return holding_.total - holding_.reserved;\n }\n}\n" + }, + "src/vaults/PoolManager.sol": { + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.28;\n\nimport {IERC20Metadata, IERC20Wrapper} from \"src/misc/interfaces/IERC20.sol\";\nimport {IERC6909MetadataExt} from \"src/misc/interfaces/IERC6909.sol\";\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {IAuth} from \"src/misc/interfaces/IAuth.sol\";\nimport {D18} from \"src/misc/types/D18.sol\";\nimport {Recoverable} from \"src/misc/Recoverable.sol\";\nimport {IERC165} from \"src/misc/interfaces/IERC7575.sol\";\nimport {ReentrancyProtection} from \"src/misc/ReentrancyProtection.sol\";\n\nimport {VaultUpdateKind, MessageLib, UpdateContractType} from \"src/common/libraries/MessageLib.sol\";\nimport {IGateway} from \"src/common/interfaces/IGateway.sol\";\nimport {IPoolManagerGatewayHandler} from \"src/common/interfaces/IGatewayHandlers.sol\";\nimport {IVaultMessageSender} from \"src/common/interfaces/IGatewaySenders.sol\";\nimport {newAssetId, AssetId} from \"src/common/types/AssetId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {PricingLib} from \"src/common/libraries/PricingLib.sol\";\n\nimport {IVaultFactory} from \"src/vaults/interfaces/factories/IVaultFactory.sol\";\nimport {IBaseVault, VaultKind} from \"src/vaults/interfaces/IBaseVaults.sol\";\nimport {IBaseRequestManager} from \"src/vaults/interfaces/investments/IBaseRequestManager.sol\";\nimport {ITokenFactory} from \"src/vaults/interfaces/factories/ITokenFactory.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\nimport {IPoolEscrowFactory} from \"src/vaults/interfaces/factories/IPoolEscrowFactory.sol\";\nimport {IHook} from \"src/common/interfaces/IHook.sol\";\nimport {IUpdateContract} from \"src/vaults/interfaces/IUpdateContract.sol\";\nimport {\n AssetIdKey,\n Pool,\n ShareClassDetails,\n Price,\n VaultDetails,\n IPoolManager\n} from \"src/vaults/interfaces/IPoolManager.sol\";\nimport {IAsyncRequestManager} from \"src/vaults/interfaces/investments/IAsyncRequestManager.sol\";\nimport {ISyncRequestManager} from \"src/vaults/interfaces/investments/ISyncRequestManager.sol\";\nimport {IPoolEscrow} from \"src/vaults/interfaces/IEscrow.sol\";\n\n/// @title Pool Manager\n/// @notice This contract manages which pools & share classes exist,\n/// as well as managing allowed pool currencies, and incoming and outgoing transfers.\ncontract PoolManager is\n Auth,\n Recoverable,\n ReentrancyProtection,\n IPoolManager,\n IUpdateContract,\n IPoolManagerGatewayHandler\n{\n using CastLib for *;\n using MessageLib for *;\n using BytesLib for bytes;\n using MathLib for uint256;\n\n uint8 internal constant MIN_DECIMALS = 2;\n uint8 internal constant MAX_DECIMALS = 18;\n\n IGateway public gateway;\n address public balanceSheet;\n ITokenFactory public tokenFactory;\n IVaultMessageSender public sender;\n IPoolEscrowFactory public poolEscrowFactory;\n IAsyncRequestManager public asyncRequestManager;\n ISyncRequestManager public syncRequestManager;\n\n uint64 internal _assetCounter;\n\n mapping(PoolId poolId => Pool) public pools;\n mapping(IVaultFactory factory => bool) public vaultFactory;\n\n mapping(IBaseVault => VaultDetails) internal _vaultDetails;\n mapping(AssetId assetId => AssetIdKey) internal _idToAsset;\n mapping(address asset => mapping(uint256 tokenId => AssetId assetId)) internal _assetToId;\n\n constructor(ITokenFactory tokenFactory_, address deployer) Auth(deployer) {\n tokenFactory = tokenFactory_;\n }\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IPoolManager\n function file(bytes32 what, address data) external auth {\n if (what == \"sender\") sender = IVaultMessageSender(data);\n else if (what == \"tokenFactory\") tokenFactory = ITokenFactory(data);\n else if (what == \"gateway\") gateway = IGateway(data);\n else if (what == \"balanceSheet\") balanceSheet = data;\n else if (what == \"poolEscrowFactory\") poolEscrowFactory = IPoolEscrowFactory(data);\n else if (what == \"asyncRequestManager\") asyncRequestManager = IAsyncRequestManager(data);\n else if (what == \"syncRequestManager\") syncRequestManager = ISyncRequestManager(data);\n else revert FileUnrecognizedParam();\n emit File(what, data);\n }\n\n /// @inheritdoc IPoolManager\n function file(bytes32 what, address factory, bool status) external auth {\n if (what == \"vaultFactory\") {\n vaultFactory[IVaultFactory(factory)] = status;\n } else {\n revert FileUnrecognizedParam();\n }\n emit File(what, factory, status);\n }\n\n //----------------------------------------------------------------------------------------------\n // Outgoing methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IPoolManager\n function transferShares(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bytes32 receiver, uint128 amount)\n external\n payable\n protected\n {\n IShareToken share = IShareToken(shareToken(poolId, scId));\n require(centrifugeId != sender.localCentrifugeId(), LocalTransferNotAllowed());\n require(\n share.checkTransferRestriction(msg.sender, address(uint160(centrifugeId)), amount),\n CrossChainTransferNotAllowed()\n );\n\n gateway.payTransaction{value: msg.value}(msg.sender);\n\n share.authTransferFrom(msg.sender, msg.sender, address(this), amount);\n share.burn(address(this), amount);\n\n emit TransferShares(centrifugeId, poolId, scId, msg.sender, receiver, amount);\n sender.sendTransferShares(centrifugeId, poolId, scId, receiver, amount);\n }\n\n // @inheritdoc IPoolManager\n function registerAsset(uint16 centrifugeId, address asset, uint256 tokenId)\n external\n payable\n protected\n returns (AssetId assetId)\n {\n string memory name;\n string memory symbol;\n uint8 decimals;\n\n decimals = _safeGetAssetDecimals(asset, tokenId);\n require(decimals >= MIN_DECIMALS, TooFewDecimals());\n require(decimals <= MAX_DECIMALS, TooManyDecimals());\n\n gateway.payTransaction{value: msg.value}(msg.sender);\n\n if (tokenId == 0) {\n IERC20Metadata meta = IERC20Metadata(asset);\n name = meta.name();\n symbol = meta.symbol();\n } else {\n IERC6909MetadataExt meta = IERC6909MetadataExt(asset);\n name = meta.name(tokenId);\n symbol = meta.symbol(tokenId);\n }\n\n assetId = _assetToId[asset][tokenId];\n if (assetId.raw() == 0) {\n _assetCounter++;\n assetId = newAssetId(sender.localCentrifugeId(), _assetCounter);\n\n _idToAsset[assetId] = AssetIdKey(asset, tokenId);\n _assetToId[asset][tokenId] = assetId;\n\n emit RegisterAsset(assetId, asset, tokenId, name, symbol, decimals);\n }\n\n sender.sendRegisterAsset(centrifugeId, assetId, decimals);\n }\n\n //----------------------------------------------------------------------------------------------\n // Incoming\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IPoolManagerGatewayHandler\n function addPool(PoolId poolId) public auth {\n Pool storage pool = pools[poolId];\n require(pool.createdAt == 0, PoolAlreadyAdded());\n pool.createdAt = block.timestamp;\n\n IPoolEscrow escrow = poolEscrowFactory.newEscrow(poolId);\n gateway.setRefundAddress(PoolId.wrap(poolId.raw()), escrow);\n\n emit AddPool(poolId);\n }\n\n /// @inheritdoc IPoolManagerGatewayHandler\n function addShareClass(\n PoolId poolId,\n ShareClassId scId,\n string memory name,\n string memory symbol,\n uint8 decimals,\n bytes32 salt,\n address hook\n ) public auth {\n require(decimals >= MIN_DECIMALS, TooFewDecimals());\n require(decimals <= MAX_DECIMALS, TooManyDecimals());\n require(isPoolActive(poolId), InvalidPool());\n\n Pool storage pool = pools[poolId];\n require(address(pool.shareClasses[scId].shareToken) == address(0), ShareClassAlreadyRegistered());\n\n // Hook can be address zero if the share token is fully permissionless and has no custom logic\n require(hook == address(0) || _isValidHook(hook), InvalidHook());\n\n address[] memory tokenWards = new address[](2);\n tokenWards[0] = address(this);\n // BalanceSheet needs this in order to mint shares\n tokenWards[1] = balanceSheet;\n\n IShareToken shareToken_ = tokenFactory.newToken(name, symbol, decimals, salt, tokenWards);\n\n if (hook != address(0)) {\n shareToken_.file(\"hook\", hook);\n }\n\n pool.shareClasses[scId].shareToken = shareToken_;\n\n emit AddShareClass(poolId, scId, shareToken_);\n }\n\n /// @inheritdoc IPoolManagerGatewayHandler\n function updateShareMetadata(PoolId poolId, ShareClassId scId, string memory name, string memory symbol)\n public\n auth\n {\n IShareToken shareToken_ = shareToken(poolId, scId);\n\n require(\n keccak256(bytes(shareToken_.name())) != keccak256(bytes(name))\n || keccak256(bytes(shareToken_.symbol())) != keccak256(bytes(symbol)),\n OldMetadata()\n );\n\n shareToken_.file(\"name\", name);\n shareToken_.file(\"symbol\", symbol);\n }\n\n /// @inheritdoc IPoolManagerGatewayHandler\n function updatePricePoolPerShare(PoolId poolId, ShareClassId scId, uint128 price, uint64 computedAt) public auth {\n ShareClassDetails storage shareClass = _shareClass(poolId, scId);\n\n require(computedAt >= shareClass.pricePoolPerShare.computedAt, CannotSetOlderPrice());\n\n shareClass.pricePoolPerShare = Price(price, computedAt, shareClass.pricePoolPerShare.maxAge);\n emit PriceUpdate(poolId, scId, price, computedAt);\n }\n\n /// @inheritdoc IPoolManagerGatewayHandler\n function updatePricePoolPerAsset(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n uint128 poolPerAsset_,\n uint64 computedAt\n ) public auth {\n ShareClassDetails storage shareClass = _shareClass(poolId, scId);\n\n (address asset, uint256 tokenId) = idToAsset(assetId);\n Price storage poolPerAsset = shareClass.pricePoolPerAsset[asset][tokenId];\n require(computedAt >= poolPerAsset.computedAt, CannotSetOlderPrice());\n\n // Disable expiration of the price\n if (poolPerAsset.computedAt == 0) {\n poolPerAsset.maxAge = type(uint64).max;\n }\n poolPerAsset.price = poolPerAsset_;\n poolPerAsset.computedAt = computedAt;\n\n emit PriceUpdate(poolId, scId, asset, tokenId, poolPerAsset_, computedAt);\n }\n\n /// @inheritdoc IPoolManagerGatewayHandler\n function updateRestriction(PoolId poolId, ShareClassId scId, bytes memory update_) public auth {\n IShareToken shareToken_ = shareToken(poolId, scId);\n address hook = shareToken_.hook();\n require(hook != address(0), InvalidHook());\n IHook(hook).updateRestriction(address(shareToken_), update_);\n }\n\n /// @inheritdoc IPoolManagerGatewayHandler\n function updateContract(PoolId poolId, ShareClassId scId, address target, bytes memory update_) public auth {\n if (target == address(this)) {\n update(poolId, scId, update_);\n } else {\n IUpdateContract(target).update(poolId, scId, update_);\n }\n\n emit UpdateContract(poolId, scId, target, update_);\n }\n\n /// @inheritdoc IPoolManagerGatewayHandler\n function updateShareHook(PoolId poolId, ShareClassId scId, address hook) public auth {\n IShareToken shareToken_ = shareToken(poolId, scId);\n require(hook != shareToken_.hook(), OldHook());\n shareToken_.file(\"hook\", hook);\n }\n\n /// @inheritdoc IPoolManagerGatewayHandler\n function handleTransferShares(PoolId poolId, ShareClassId scId, address destinationAddress, uint128 amount)\n public\n auth\n {\n IShareToken shareToken_ = shareToken(poolId, scId);\n\n shareToken_.mint(destinationAddress, amount);\n }\n\n /// @inheritdoc IUpdateContract\n /// @notice The pool manager either deploys the vault if a factory address is provided\n /// or it simply links/unlinks the vault.\n function update(PoolId poolId, ShareClassId scId, bytes memory payload) public auth {\n uint8 kind = uint8(MessageLib.updateContractType(payload));\n\n if (kind == uint8(UpdateContractType.VaultUpdate)) {\n MessageLib.UpdateContractVaultUpdate memory m = MessageLib.deserializeUpdateContractVaultUpdate(payload);\n\n if (m.kind == uint8(VaultUpdateKind.DeployAndLink)) {\n IVaultFactory factory = IVaultFactory(m.vaultOrFactory.toAddress());\n\n IBaseVault vault = deployVault(poolId, scId, AssetId.wrap(m.assetId), factory);\n linkVault(poolId, scId, AssetId.wrap(m.assetId), vault);\n } else {\n IBaseVault vault = IBaseVault(m.vaultOrFactory.toAddress());\n\n // Needed as safeguard against non-validated vaults\n // I.e. we only accept vaults that have been deployed by the pool manager\n require(_vaultDetails[vault].asset != address(0), UnknownVault());\n\n if (m.kind == uint8(VaultUpdateKind.Link)) {\n linkVault(poolId, scId, AssetId.wrap(m.assetId), vault);\n } else if (m.kind == uint8(VaultUpdateKind.Unlink)) {\n unlinkVault(poolId, scId, AssetId.wrap(m.assetId), vault);\n } else {\n revert MalformedVaultUpdateMessage();\n }\n }\n } else if (kind == uint8(UpdateContractType.MaxAssetPriceAge)) {\n MessageLib.UpdateContractMaxAssetPriceAge memory m =\n MessageLib.deserializeUpdateContractMaxAssetPriceAge(payload);\n\n ShareClassDetails storage shareClass = _shareClass(poolId, scId);\n require(m.assetId != 0, UnknownAsset());\n\n (address asset, uint256 tokenId) = idToAsset(AssetId.wrap(m.assetId));\n shareClass.pricePoolPerAsset[asset][tokenId].maxAge = m.maxPriceAge;\n emit UpdateMaxAssetPriceAge(poolId, scId, asset, tokenId, m.maxPriceAge);\n } else if (kind == uint8(UpdateContractType.MaxSharePriceAge)) {\n MessageLib.UpdateContractMaxSharePriceAge memory m =\n MessageLib.deserializeUpdateContractMaxSharePriceAge(payload);\n\n ShareClassDetails storage shareClass = _shareClass(poolId, scId);\n\n shareClass.pricePoolPerShare.maxAge = m.maxPriceAge;\n emit UpdateMaxSharePriceAge(poolId, scId, m.maxPriceAge);\n } else {\n revert UnknownUpdateContractType();\n }\n }\n\n /// @inheritdoc IPoolManager\n function linkVault(PoolId poolId, ShareClassId scId, AssetId assetId, IBaseVault vault) public auth {\n _shareClass(poolId, scId);\n\n AssetIdKey memory assetIdKey = _idToAsset[assetId];\n\n IBaseRequestManager manager = vault.manager();\n manager.addVault(poolId, scId, vault, assetIdKey.asset, assetId);\n\n _vaultDetails[vault].isLinked = true;\n\n emit LinkVault(poolId, scId, assetIdKey.asset, assetIdKey.tokenId, vault);\n }\n\n /// @inheritdoc IPoolManager\n function unlinkVault(PoolId poolId, ShareClassId scId, AssetId assetId, IBaseVault vault) public auth {\n _shareClass(poolId, scId);\n\n AssetIdKey memory assetIdKey = _idToAsset[assetId];\n\n IBaseRequestManager manager = vault.manager();\n manager.removeVault(poolId, scId, vault, assetIdKey.asset, assetId);\n\n _vaultDetails[vault].isLinked = false;\n\n emit UnlinkVault(poolId, scId, assetIdKey.asset, assetIdKey.tokenId, vault);\n }\n\n /// @inheritdoc IPoolManager\n function deployVault(PoolId poolId, ShareClassId scId, AssetId assetId, IVaultFactory factory)\n public\n auth\n returns (IBaseVault)\n {\n ShareClassDetails storage shareClass = _shareClass(poolId, scId);\n require(vaultFactory[factory], InvalidFactory());\n\n // Rely investment manager on vault so it can mint tokens\n address[] memory vaultWards = new address[](0);\n\n // Deploy vault\n AssetIdKey memory assetIdKey = _idToAsset[assetId];\n IBaseVault vault = IVaultFactory(factory).newVault(\n poolId, scId, assetIdKey.asset, assetIdKey.tokenId, shareClass.shareToken, vaultWards\n );\n\n // Check whether asset is an ERC20 token wrapper\n (bool success, bytes memory data) =\n assetIdKey.asset.staticcall(abi.encodeWithSelector(IERC20Wrapper.underlying.selector));\n // On success, the returned 20 byte address is padded to 32 bytes\n bool isWrappedERC20 = success && data.length == 32;\n _vaultDetails[vault] = VaultDetails(assetId, assetIdKey.asset, assetIdKey.tokenId, isWrappedERC20, false);\n\n // NOTE - Reverting the manager approvals is not easy. We SHOULD do that if we phase-out a manager\n VaultKind vaultKind = _relyShareToken(vault, shareClass.shareToken);\n\n emit DeployVault(poolId, scId, assetIdKey.asset, assetIdKey.tokenId, factory, vault, vaultKind);\n return vault;\n }\n\n //----------------------------------------------------------------------------------------------\n // View methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IPoolManager\n function isPoolActive(PoolId poolId) public view returns (bool) {\n return pools[poolId].createdAt > 0;\n }\n\n /// @inheritdoc IPoolManager\n function shareToken(PoolId poolId, ShareClassId scId) public view returns (IShareToken) {\n ShareClassDetails storage shareClass = pools[poolId].shareClasses[scId];\n require(address(shareClass.shareToken) != address(0), UnknownToken());\n return shareClass.shareToken;\n }\n\n /// @inheritdoc IPoolManager\n function vaultDetails(IBaseVault vault) public view returns (VaultDetails memory details) {\n details = _vaultDetails[vault];\n require(details.asset != address(0), UnknownVault());\n }\n\n /// @inheritdoc IPoolManager\n function isLinked(PoolId, /* poolId */ ShareClassId, /* scId */ address, /* asset */ IBaseVault vault)\n public\n view\n returns (bool)\n {\n return _vaultDetails[vault].isLinked;\n }\n\n /// @inheritdoc IPoolManager\n function idToAsset(AssetId assetId) public view returns (address asset, uint256 tokenId) {\n AssetIdKey memory assetIdKey = _idToAsset[assetId];\n require(assetIdKey.asset != address(0), UnknownAsset());\n return (assetIdKey.asset, assetIdKey.tokenId);\n }\n\n /// @inheritdoc IPoolManager\n function assetToId(address asset, uint256 tokenId) public view returns (AssetId assetId) {\n assetId = _assetToId[asset][tokenId];\n require(assetId.raw() != 0, UnknownAsset());\n }\n\n /// @inheritdoc IPoolManager\n function priceAssetPerShare(PoolId poolId, ShareClassId scId, AssetId assetId, bool checkValidity)\n public\n view\n returns (D18 price)\n {\n (Price memory poolPerAsset, Price memory poolPerShare) = _pricesPoolPer(poolId, scId, assetId, checkValidity);\n\n price = PricingLib.priceAssetPerShare(poolPerShare.asPrice(), poolPerAsset.asPrice());\n }\n\n /// @inheritdoc IPoolManager\n function pricePoolPerShare(PoolId poolId, ShareClassId scId, bool checkValidity) public view returns (D18 price) {\n ShareClassDetails storage shareClass = _shareClass(poolId, scId);\n\n if (checkValidity) {\n require(shareClass.pricePoolPerShare.isValid(), InvalidPrice());\n }\n\n price = shareClass.pricePoolPerShare.asPrice();\n }\n\n /// @inheritdoc IPoolManager\n function pricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId, bool checkValidity)\n public\n view\n returns (D18 price)\n {\n (Price memory poolPerAsset,) = _pricesPoolPer(poolId, scId, assetId, false);\n\n if (checkValidity) {\n require(poolPerAsset.isValid(), InvalidPrice());\n }\n\n price = poolPerAsset.asPrice();\n }\n\n /// @inheritdoc IPoolManager\n function pricesPoolPer(PoolId poolId, ShareClassId scId, AssetId assetId, bool checkValidity)\n public\n view\n returns (D18 pricePoolPerAsset_, D18 pricePoolPerShare_)\n {\n (Price memory poolPerAsset, Price memory poolPerShare) = _pricesPoolPer(poolId, scId, assetId, checkValidity);\n return (poolPerAsset.asPrice(), poolPerShare.asPrice());\n }\n\n /// @inheritdoc IPoolManager\n function markersPricePoolPerShare(PoolId poolId, ShareClassId scId)\n external\n view\n returns (uint64 computedAt, uint64 maxAge, uint64 validUntil)\n {\n ShareClassDetails storage shareClass = _shareClass(poolId, scId);\n computedAt = shareClass.pricePoolPerShare.computedAt;\n maxAge = shareClass.pricePoolPerShare.maxAge;\n validUntil = shareClass.pricePoolPerShare.validUntil();\n }\n\n /// @inheritdoc IPoolManager\n function markersPricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId)\n external\n view\n returns (uint64 computedAt, uint64 maxAge, uint64 validUntil)\n {\n (Price memory poolPerAsset,) = _pricesPoolPer(poolId, scId, assetId, false);\n computedAt = poolPerAsset.computedAt;\n maxAge = poolPerAsset.maxAge;\n validUntil = poolPerAsset.validUntil();\n }\n\n //----------------------------------------------------------------------------------------------\n // Internal methods\n //----------------------------------------------------------------------------------------------\n\n function _pricesPoolPer(PoolId poolId, ShareClassId scId, AssetId assetId, bool checkValidity)\n internal\n view\n returns (Price memory poolPerAsset, Price memory poolPerShare)\n {\n ShareClassDetails storage shareClass = _shareClass(poolId, scId);\n\n (address asset, uint256 tokenId) = idToAsset(assetId);\n poolPerAsset = shareClass.pricePoolPerAsset[asset][tokenId];\n poolPerShare = shareClass.pricePoolPerShare;\n\n if (checkValidity) {\n require(poolPerAsset.isValid(), InvalidPrice());\n require(poolPerShare.isValid(), InvalidPrice());\n }\n }\n\n /// @dev Sets up approval permissions for pool, i.e. the pool escrow, the base vault manager and potentially a\n /// secondary manager (in case of partially sync vault)\n function _relyShareToken(IBaseVault vault, IShareToken shareToken_) internal returns (VaultKind) {\n IBaseRequestManager manager = vault.manager();\n IAuth(address(shareToken_)).rely(address(manager));\n\n // For sync deposit & async redeem vault, also repeat above for async manager\n VaultKind vaultKind = vault.vaultKind();\n if (vaultKind == VaultKind.SyncDepositAsyncRedeem) {\n IAuth(address(shareToken_)).rely(address(asyncRequestManager));\n }\n\n return vaultKind;\n }\n\n function _safeGetAssetDecimals(address asset, uint256 tokenId) private view returns (uint8) {\n bytes memory callData;\n\n if (tokenId == 0) {\n callData = abi.encodeWithSignature(\"decimals()\");\n } else {\n callData = abi.encodeWithSignature(\"decimals(uint256)\", tokenId);\n }\n\n (bool success, bytes memory data) = asset.staticcall(callData);\n require(success && data.length >= 32, AssetMissingDecimals());\n\n return abi.decode(data, (uint8));\n }\n\n function _isValidHook(address hook) internal view returns (bool) {\n (bool success, bytes memory data) =\n hook.staticcall(abi.encodeWithSelector(IERC165.supportsInterface.selector, type(IHook).interfaceId));\n\n return success && data.length == 32 && abi.decode(data, (bool));\n }\n\n function _shareClass(PoolId poolId, ShareClassId scId)\n internal\n view\n returns (ShareClassDetails storage shareClass)\n {\n shareClass = pools[poolId].shareClasses[scId];\n require(address(shareClass.shareToken) != address(0), ShareTokenDoesNotExist());\n }\n}\n" + }, + "src/vaults/SyncDepositVault.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IERC165} from \"src/misc/interfaces/IERC7575.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nimport {BaseVault, BaseAsyncRedeemVault, BaseSyncDepositVault} from \"src/vaults/BaseVaults.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\nimport {IAsyncRedeemManager} from \"src/vaults/interfaces/investments/IAsyncRedeemManager.sol\";\nimport {ISyncDepositManager} from \"src/vaults/interfaces/investments/ISyncDepositManager.sol\";\nimport {IBaseRequestManager} from \"src/vaults/interfaces/investments/IBaseRequestManager.sol\";\nimport {VaultKind} from \"src/vaults/interfaces/IBaseVaults.sol\";\n\n/// @title SyncDepositVault\n/// @notice Partially (a)synchronous Tokenized Vault implementation with synchronous deposits\n/// and asynchronous redemptions following ERC-7540.\n///\n/// @dev Each vault issues shares of Centrifuge share class tokens as restricted ERC-20 tokens\n/// against asset deposits based on the current share price.\ncontract SyncDepositVault is BaseSyncDepositVault, BaseAsyncRedeemVault {\n constructor(\n PoolId poolId_,\n ShareClassId scId_,\n address asset_,\n IShareToken token_,\n address root_,\n ISyncDepositManager syncDepositManager_,\n IAsyncRedeemManager asyncRedeemManager_\n )\n BaseVault(poolId_, scId_, asset_, token_, root_, syncDepositManager_)\n BaseSyncDepositVault(syncDepositManager_)\n BaseAsyncRedeemVault(asyncRedeemManager_)\n {}\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n function file(bytes32 what, address data) external override(BaseAsyncRedeemVault, BaseVault) auth {\n if (what == \"manager\") manager = IBaseRequestManager(data);\n else if (what == \"asyncRedeemManager\") asyncRedeemManager = IAsyncRedeemManager(data);\n else if (what == \"syncDepositManager\") syncDepositManager = ISyncDepositManager(data);\n else revert FileUnrecognizedParam();\n emit File(what, data);\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-165\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC165\n function supportsInterface(bytes4 interfaceId)\n public\n pure\n override(BaseAsyncRedeemVault, BaseSyncDepositVault)\n returns (bool)\n {\n return super.supportsInterface(interfaceId);\n }\n\n //----------------------------------------------------------------------------------------------\n // IBaseVault view\n //----------------------------------------------------------------------------------------------\n\n function vaultKind() public pure returns (VaultKind vaultKind_) {\n return VaultKind.SyncDepositAsyncRedeem;\n }\n}\n" + }, + "src/vaults/SyncRequestManager.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IERC165} from \"forge-std/interfaces/IERC165.sol\";\nimport {IERC7540Redeem} from \"src/misc/interfaces/IERC7540.sol\";\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {IAuth} from \"src/misc/interfaces/IAuth.sol\";\nimport {d18, D18} from \"src/misc/types/D18.sol\";\n\nimport {MessageLib, UpdateContractType} from \"src/common/libraries/MessageLib.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {PricingLib} from \"src/common/libraries/PricingLib.sol\";\n\nimport {BaseRequestManager} from \"src/vaults/BaseRequestManager.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\nimport {IAsyncRedeemVault, IBaseVault, VaultKind} from \"src/vaults/interfaces/IBaseVaults.sol\";\nimport {IPoolManager, VaultDetails} from \"src/vaults/interfaces/IPoolManager.sol\";\nimport {IBalanceSheet} from \"src/vaults/interfaces/IBalanceSheet.sol\";\nimport {IBaseRequestManager} from \"src/vaults/interfaces/investments/IBaseRequestManager.sol\";\nimport {\n ISyncRequestManager,\n Prices,\n ISyncDepositValuation\n} from \"src/vaults/interfaces/investments/ISyncRequestManager.sol\";\nimport {IDepositManager} from \"src/vaults/interfaces/investments/IDepositManager.sol\";\nimport {ISyncDepositManager} from \"src/vaults/interfaces/investments/ISyncDepositManager.sol\";\nimport {IUpdateContract} from \"src/vaults/interfaces/IUpdateContract.sol\";\nimport {IEscrow} from \"src/vaults/interfaces/IEscrow.sol\";\nimport {IPoolEscrowProvider} from \"src/vaults/interfaces/factories/IPoolEscrowFactory.sol\";\nimport {IAsyncRedeemManager} from \"src/vaults/interfaces/investments/IAsyncRedeemManager.sol\";\n\n/// @title Sync Investment Manager\n/// @notice This is the main contract vaults interact with for\n/// both incoming and outgoing investment transactions.\ncontract SyncRequestManager is BaseRequestManager, ISyncRequestManager {\n using BytesLib for bytes;\n using MathLib for *;\n using CastLib for *;\n using MessageLib for *;\n\n IBalanceSheet public balanceSheet;\n\n mapping(PoolId => mapping(ShareClassId scId => ISyncDepositValuation)) public valuation;\n mapping(PoolId => mapping(ShareClassId scId => mapping(address asset => mapping(uint256 tokenId => uint128))))\n public maxReserve;\n\n constructor(IEscrow globalEscrow_, address root_, address deployer)\n BaseRequestManager(globalEscrow_, root_, deployer)\n {}\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IBaseRequestManager\n function file(bytes32 what, address data) external override(IBaseRequestManager, BaseRequestManager) auth {\n if (what == \"poolManager\") poolManager = IPoolManager(data);\n else if (what == \"balanceSheet\") balanceSheet = IBalanceSheet(data);\n else if (what == \"poolEscrowProvider\") poolEscrowProvider = IPoolEscrowProvider(data);\n else revert FileUnrecognizedParam();\n emit File(what, data);\n }\n\n /// @inheritdoc IUpdateContract\n function update(PoolId poolId, ShareClassId scId, bytes memory payload) external auth {\n uint8 kind = uint8(MessageLib.updateContractType(payload));\n\n if (kind == uint8(UpdateContractType.Valuation)) {\n MessageLib.UpdateContractValuation memory m = MessageLib.deserializeUpdateContractValuation(payload);\n\n require(address(poolManager.shareToken(poolId, scId)) != address(0), ShareTokenDoesNotExist());\n\n setValuation(poolId, scId, m.valuation.toAddress());\n } else if (kind == uint8(UpdateContractType.SyncDepositMaxReserve)) {\n MessageLib.UpdateContractSyncDepositMaxReserve memory m =\n MessageLib.deserializeUpdateContractSyncDepositMaxReserve(payload);\n\n require(address(poolManager.shareToken(poolId, scId)) != address(0), ShareTokenDoesNotExist());\n (address asset, uint256 tokenId) = poolManager.idToAsset(AssetId.wrap(m.assetId));\n\n setMaxReserve(poolId, scId, asset, tokenId, m.maxReserve);\n } else {\n revert UnknownUpdateContractType();\n }\n }\n\n /// @inheritdoc IBaseRequestManager\n function addVault(PoolId poolId, ShareClassId scId, IBaseVault vault_, address asset_, AssetId assetId)\n public\n override(BaseRequestManager, IBaseRequestManager)\n auth\n {\n super.addVault(poolId, scId, vault_, asset_, assetId);\n\n (, uint256 tokenId) = poolManager.idToAsset(assetId);\n setMaxReserve(poolId, scId, asset_, tokenId, type(uint128).max);\n\n VaultKind vaultKind_ = vault_.vaultKind();\n if (vaultKind_ == VaultKind.SyncDepositAsyncRedeem) {\n IAsyncRedeemManager asyncRequestManager = IAsyncRedeemVault(address(vault_)).asyncRedeemManager();\n require(address(asyncRequestManager) != address(0), SecondaryManagerDoesNotExist());\n asyncRequestManager.addVault(poolId, scId, vault_, asset_, assetId);\n }\n }\n\n /// @inheritdoc IBaseRequestManager\n function removeVault(PoolId poolId, ShareClassId scId, IBaseVault vault_, address asset_, AssetId assetId)\n public\n override(BaseRequestManager, IBaseRequestManager)\n auth\n {\n super.removeVault(poolId, scId, vault_, asset_, assetId);\n\n (, uint256 tokenId) = poolManager.idToAsset(assetId);\n delete maxReserve[poolId][scId][asset_][tokenId];\n\n VaultKind vaultKind_ = vault_.vaultKind();\n if (vaultKind_ == VaultKind.SyncDepositAsyncRedeem) {\n IAsyncRedeemManager asyncRequestManager = IAsyncRedeemVault(address(vault_)).asyncRedeemManager();\n require(address(asyncRequestManager) != address(0), SecondaryManagerDoesNotExist());\n asyncRequestManager.removeVault(poolId, scId, vault_, asset_, assetId);\n }\n }\n\n /// @inheritdoc ISyncRequestManager\n function setValuation(PoolId poolId, ShareClassId scId, address valuation_) public auth {\n valuation[poolId][scId] = ISyncDepositValuation(valuation_);\n\n emit SetValuation(poolId, scId, address(valuation_));\n }\n\n /// @inheritdoc ISyncRequestManager\n function setMaxReserve(PoolId poolId, ShareClassId scId, address asset, uint256 tokenId, uint128 maxReserve_)\n public\n auth\n {\n maxReserve[poolId][scId][asset][tokenId] = maxReserve_;\n\n emit SetMaxReserve(poolId, scId, asset, tokenId, maxReserve_);\n }\n\n //----------------------------------------------------------------------------------------------\n // Deposit handlers\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IDepositManager\n function mint(IBaseVault vault_, uint256 shares, address receiver, address owner)\n external\n auth\n returns (uint256 assets)\n {\n require(maxMint(vault_, owner) >= shares, ExceedsMaxMint());\n assets = previewMint(vault_, owner, shares);\n\n _issueShares(vault_, shares.toUint128(), receiver, owner, assets.toUint128());\n }\n\n /// @inheritdoc IDepositManager\n function deposit(IBaseVault vault_, uint256 assets, address receiver, address owner)\n external\n auth\n returns (uint256 shares)\n {\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n require(poolManager.isLinked(vault_.poolId(), vault_.scId(), vaultDetails.asset, vault_), AssetNotAllowed());\n\n require(maxDeposit(vault_, owner) >= assets, ExceedsMaxDeposit());\n shares = previewDeposit(vault_, owner, assets);\n\n _issueShares(vault_, shares.toUint128(), receiver, owner, assets.toUint128());\n }\n\n //----------------------------------------------------------------------------------------------\n // View methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc ISyncDepositManager\n function previewMint(IBaseVault vault_, address, /* sender */ uint256 shares)\n public\n view\n returns (uint256 assets)\n {\n return _shareToAssetAmount(vault_, shares, MathLib.Rounding.Up);\n }\n\n /// @inheritdoc ISyncDepositManager\n function previewDeposit(IBaseVault vault_, address, /* sender */ uint256 assets)\n public\n view\n returns (uint256 shares)\n {\n return convertToShares(vault_, assets);\n }\n\n /// @inheritdoc IDepositManager\n function maxMint(IBaseVault vault_, address /* owner */ ) public view returns (uint256) {\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n uint128 maxAssets = _maxDeposit(vault_.poolId(), vault_.scId(), vaultDetails.asset, vaultDetails.tokenId);\n return convertToShares(vault_, maxAssets);\n }\n\n /// @inheritdoc IDepositManager\n function maxDeposit(IBaseVault vault_, address /* owner */ ) public view returns (uint256) {\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n return _maxDeposit(vault_.poolId(), vault_.scId(), vaultDetails.asset, vaultDetails.tokenId);\n }\n\n /// @inheritdoc IBaseRequestManager\n function convertToShares(IBaseVault vault_, uint256 assets)\n public\n view\n override(IBaseRequestManager, BaseRequestManager)\n returns (uint256 shares)\n {\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n Prices memory prices_ = prices(vault_.poolId(), vault_.scId(), vaultDetails.assetId);\n\n return super._assetToShareAmount(\n vault_, vaultDetails, assets, prices_.poolPerAsset, prices_.poolPerShare, MathLib.Rounding.Down\n );\n }\n\n /// @inheritdoc IBaseRequestManager\n function convertToAssets(IBaseVault vault_, uint256 shares)\n public\n view\n override(IBaseRequestManager, BaseRequestManager)\n returns (uint256 assets)\n {\n return _shareToAssetAmount(vault_, shares, MathLib.Rounding.Down);\n }\n\n /// @inheritdoc ISyncDepositValuation\n function pricePoolPerShare(PoolId poolId, ShareClassId scId) public view returns (D18 price) {\n ISyncDepositValuation valuation_ = valuation[poolId][scId];\n\n if (address(valuation_) == address(0)) {\n price = poolManager.pricePoolPerShare(poolId, scId, true);\n } else {\n price = valuation_.pricePoolPerShare(poolId, scId);\n }\n }\n\n /// @inheritdoc ISyncRequestManager\n function prices(PoolId poolId, ShareClassId scId, AssetId assetId) public view returns (Prices memory priceData) {\n priceData.poolPerShare = pricePoolPerShare(poolId, scId);\n priceData.poolPerAsset = poolManager.pricePoolPerAsset(poolId, scId, assetId, true);\n priceData.assetPerShare = PricingLib.priceAssetPerShare(priceData.poolPerShare, priceData.poolPerAsset);\n }\n\n //----------------------------------------------------------------------------------------------\n // Internal\n //----------------------------------------------------------------------------------------------\n\n /// @dev Issues shares to the receiver and instruct the balance sheet\n // to react on the issuance and the updated holding.\n function _issueShares(IBaseVault vault_, uint128 shares, address receiver, address, /* owner */ uint128 assets)\n internal\n {\n PoolId poolId = vault_.poolId();\n ShareClassId scId = vault_.scId();\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n\n balanceSheet.overridePricePoolPerShare(poolId, scId, prices(poolId, scId, vaultDetails.assetId).poolPerShare);\n balanceSheet.issue(poolId, scId, receiver, shares);\n\n // Note deposit into the pool escrow, to make assets available for managers of the balance sheet\n // ERC-20 transfer is handled by the vault to the pool escrow afterwards\n balanceSheet.noteDeposit(poolId, scId, vaultDetails.asset, vaultDetails.tokenId, receiver, assets);\n }\n\n function _maxDeposit(PoolId poolId, ShareClassId scId, address asset, uint256 tokenId)\n internal\n view\n returns (uint128 maxDeposit_)\n {\n uint128 availableBalance = poolEscrowProvider.escrow(poolId).availableBalanceOf(scId, asset, tokenId);\n uint128 maxReserve_ = maxReserve[poolId][scId][asset][tokenId];\n\n if (maxReserve_ < availableBalance) {\n maxDeposit_ = 0;\n } else {\n maxDeposit_ = maxReserve_ - availableBalance;\n }\n }\n\n function _shareToAssetAmount(IBaseVault vault_, uint256 assets, MathLib.Rounding rounding)\n internal\n view\n returns (uint256 shares)\n {\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n Prices memory prices_ = prices(vault_.poolId(), vault_.scId(), vaultDetails.assetId);\n return super._shareToAssetAmount(\n vault_, vaultDetails, assets, prices_.poolPerAsset, prices_.poolPerShare, rounding\n );\n }\n}\n" + }, + "src/vaults/VaultRouter.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {Multicall, IMulticall} from \"src/misc/Multicall.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {SafeTransferLib} from \"src/misc/libraries/SafeTransferLib.sol\";\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {IERC20, IERC20Permit, IERC20Wrapper} from \"src/misc/interfaces/IERC20.sol\";\nimport {IERC7540Deposit} from \"src/misc/interfaces/IERC7540.sol\";\nimport {Recoverable} from \"src/misc/Recoverable.sol\";\n\nimport {IGateway} from \"src/common/interfaces/IGateway.sol\";\nimport {IMessageDispatcher} from \"src/common/interfaces/IMessageDispatcher.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nimport {IAsyncVault, IBaseVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\nimport {IVaultRouter} from \"src/vaults/interfaces/IVaultRouter.sol\";\nimport {IPoolManager, VaultDetails} from \"src/vaults/interfaces/IPoolManager.sol\";\nimport {IEscrow} from \"src/vaults/interfaces/IEscrow.sol\";\nimport {BaseSyncDepositVault} from \"src/vaults/BaseVaults.sol\";\n\n/// @title VaultRouter\n/// @notice This is a helper contract, designed to be the entrypoint for EOAs.\n/// It removes the need to know about all other contracts and simplifies the way to interact with the protocol.\n/// It also adds the need to fully pay for each step of the transaction execution. VaultRouter allows\n/// the caller to execute multiple function into a single transaction by taking advantage of\n/// the multicall functionality which batches message calls into a single one.\n/// @dev It is critical to ensure that at the end of any transaction, no funds remain in the\n/// VaultRouter. Any funds that do remain are at risk of being taken by other users.\ncontract VaultRouter is Auth, Multicall, Recoverable, IVaultRouter {\n using CastLib for address;\n\n /// @dev Requests for Centrifuge pool are non-fungible and all have ID = 0\n uint256 private constant REQUEST_ID = 0;\n\n IEscrow public immutable escrow;\n IGateway public immutable gateway;\n IPoolManager public immutable poolManager;\n IMessageDispatcher public immutable messageDispatcher;\n\n /// @inheritdoc IVaultRouter\n mapping(address controller => mapping(IBaseVault vault => uint256 amount)) public lockedRequests;\n\n constructor(\n address escrow_,\n IGateway gateway_,\n IPoolManager poolManager_,\n IMessageDispatcher messageDispatcher_,\n address deployer\n ) Auth(deployer) {\n escrow = IEscrow(escrow_);\n gateway = gateway_;\n poolManager = poolManager_;\n messageDispatcher = messageDispatcher_;\n }\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IMulticall\n /// @notice performs a multicall but all message sent in the process will be batched\n function multicall(bytes[] calldata data) public payable override(Multicall, IMulticall) {\n bool wasBatching = gateway.isBatching();\n if (!wasBatching) {\n gateway.startBatching();\n gateway.payTransaction{value: msg.value}(msg.sender);\n }\n\n super.multicall(data);\n\n if (!wasBatching) {\n gateway.endBatching();\n }\n }\n\n //----------------------------------------------------------------------------------------------\n // Enable interactions\n //----------------------------------------------------------------------------------------------\n\n function enable(IBaseVault vault) public payable protected {\n vault.setEndorsedOperator(msg.sender, true);\n }\n\n function disable(IBaseVault vault) external payable protected {\n vault.setEndorsedOperator(msg.sender, false);\n }\n\n //----------------------------------------------------------------------------------------------\n // Deposit\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IVaultRouter\n function requestDeposit(IAsyncVault vault, uint256 amount, address controller, address owner)\n external\n payable\n protected\n {\n require(owner == msg.sender || owner == address(this), InvalidOwner());\n\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault);\n if (owner == address(this)) {\n _approveMax(vaultDetails.asset, address(vault));\n }\n\n _pay();\n vault.requestDeposit(amount, controller, owner);\n }\n\n /// @inheritdoc IVaultRouter\n function deposit(BaseSyncDepositVault vault, uint256 assets, address receiver, address owner)\n external\n payable\n protected\n {\n require(owner == msg.sender || owner == address(this), InvalidOwner());\n require(!vault.supportsInterface(type(IERC7540Deposit).interfaceId), NonSyncDepositVault());\n\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault);\n SafeTransferLib.safeTransferFrom(vaultDetails.asset, owner, address(this), assets);\n _approveMax(vaultDetails.asset, address(vault));\n\n _pay();\n vault.deposit(assets, receiver);\n }\n\n /// @inheritdoc IVaultRouter\n function lockDepositRequest(IBaseVault vault, uint256 amount, address controller, address owner)\n public\n payable\n protected\n {\n require(owner == msg.sender || owner == address(this), InvalidOwner());\n require(vault.supportsInterface(type(IERC7540Deposit).interfaceId), NonAsyncVault());\n\n lockedRequests[controller][vault] += amount;\n\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault);\n SafeTransferLib.safeTransferFrom(vaultDetails.asset, owner, address(escrow), amount);\n\n emit LockDepositRequest(vault, controller, owner, msg.sender, amount);\n }\n\n /// @inheritdoc IVaultRouter\n function enableLockDepositRequest(IBaseVault vault, uint256 amount) external payable protected {\n enable(vault);\n\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault);\n\n uint256 assetBalance;\n assetBalance = IERC20(vaultDetails.asset).balanceOf(msg.sender);\n\n if (vaultDetails.isWrapper && assetBalance < amount) {\n wrap(vaultDetails.asset, amount, address(this), msg.sender);\n lockDepositRequest(vault, amount, msg.sender, address(this));\n } else {\n lockDepositRequest(vault, amount, msg.sender, msg.sender);\n }\n }\n\n /// @inheritdoc IVaultRouter\n function unlockDepositRequest(IBaseVault vault, address receiver) external payable protected {\n uint256 lockedRequest = lockedRequests[msg.sender][vault];\n require(lockedRequest != 0, NoLockedBalance());\n lockedRequests[msg.sender][vault] = 0;\n\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault);\n escrow.authTransferTo(vaultDetails.asset, receiver, lockedRequest);\n\n emit UnlockDepositRequest(vault, msg.sender, receiver);\n }\n\n /// @inheritdoc IVaultRouter\n function executeLockedDepositRequest(IAsyncVault vault, address controller) external payable protected {\n uint256 lockedRequest = lockedRequests[controller][vault];\n require(lockedRequest != 0, NoLockedRequest());\n lockedRequests[controller][vault] = 0;\n\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault);\n escrow.authTransferTo(vaultDetails.asset, address(this), lockedRequest);\n\n _pay();\n _approveMax(vaultDetails.asset, address(vault));\n vault.requestDeposit(lockedRequest, controller, address(this));\n emit ExecuteLockedDepositRequest(vault, controller, msg.sender);\n }\n\n /// @inheritdoc IVaultRouter\n function claimDeposit(IAsyncVault vault, address receiver, address controller) external payable protected {\n _canClaim(vault, receiver, controller);\n uint256 maxMint = vault.maxMint(controller);\n vault.mint(maxMint, receiver, controller);\n }\n\n /// @inheritdoc IVaultRouter\n function cancelDepositRequest(IAsyncVault vault) external payable protected {\n _pay();\n vault.cancelDepositRequest(REQUEST_ID, msg.sender);\n }\n\n /// @inheritdoc IVaultRouter\n function claimCancelDepositRequest(IAsyncVault vault, address receiver, address controller)\n external\n payable\n protected\n {\n _canClaim(vault, receiver, controller);\n vault.claimCancelDepositRequest(REQUEST_ID, receiver, controller);\n }\n\n //----------------------------------------------------------------------------------------------\n // Redeem\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IVaultRouter\n function requestRedeem(IAsyncVault vault, uint256 amount, address controller, address owner)\n external\n payable\n protected\n {\n require(owner == msg.sender || owner == address(this), InvalidOwner());\n _pay();\n vault.requestRedeem(amount, controller, owner);\n }\n\n /// @inheritdoc IVaultRouter\n function claimRedeem(IBaseVault vault, address receiver, address controller) external payable protected {\n _canClaim(vault, receiver, controller);\n uint256 maxWithdraw = vault.maxWithdraw(controller);\n\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault);\n if (vaultDetails.isWrapper && controller != msg.sender) {\n // Auto-unwrap if permissionlessly claiming for another controller\n vault.withdraw(maxWithdraw, address(this), controller);\n unwrap(vaultDetails.asset, maxWithdraw, receiver);\n } else {\n vault.withdraw(maxWithdraw, receiver, controller);\n }\n }\n\n /// @inheritdoc IVaultRouter\n function cancelRedeemRequest(IAsyncVault vault) external payable protected {\n _pay();\n vault.cancelRedeemRequest(REQUEST_ID, msg.sender);\n }\n\n /// @inheritdoc IVaultRouter\n function claimCancelRedeemRequest(IAsyncVault vault, address receiver, address controller)\n external\n payable\n protected\n {\n _canClaim(vault, receiver, controller);\n vault.claimCancelRedeemRequest(REQUEST_ID, receiver, controller);\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-20 permits & wrapping\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IVaultRouter\n function permit(address asset, address spender, uint256 assets, uint256 deadline, uint8 v, bytes32 r, bytes32 s)\n external\n payable\n protected\n {\n try IERC20Permit(asset).permit(msg.sender, spender, assets, deadline, v, r, s) {} catch {}\n }\n\n function wrap(address wrapper, uint256 amount, address receiver, address owner) public payable protected {\n require(owner == msg.sender || owner == address(this), InvalidOwner());\n address underlying = IERC20Wrapper(wrapper).underlying();\n\n amount = MathLib.min(amount, IERC20(underlying).balanceOf(owner));\n require(amount != 0, ZeroBalance());\n SafeTransferLib.safeTransferFrom(underlying, owner, address(this), amount);\n\n _approveMax(underlying, wrapper);\n require(IERC20Wrapper(wrapper).depositFor(receiver, amount), WrapFailed());\n }\n\n function unwrap(address wrapper, uint256 amount, address receiver) public payable protected {\n amount = MathLib.min(amount, IERC20(wrapper).balanceOf(address(this)));\n require(amount != 0, ZeroBalance());\n\n require(IERC20Wrapper(wrapper).withdrawTo(receiver, amount), UnwrapFailed());\n }\n\n //----------------------------------------------------------------------------------------------\n // View methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IVaultRouter\n function getVault(PoolId poolId, ShareClassId scId, address asset) external view returns (address) {\n return IPoolManager(poolManager).shareToken(poolId, scId).vault(asset);\n }\n\n /// @inheritdoc IVaultRouter\n function estimate(uint16 centrifugeId, bytes calldata payload) external view returns (uint256) {\n return messageDispatcher.estimate(centrifugeId, payload);\n }\n\n /// @inheritdoc IVaultRouter\n function hasPermissions(IBaseVault vault, address controller) external view returns (bool) {\n return vault.isPermissioned(controller);\n }\n\n /// @inheritdoc IVaultRouter\n function isEnabled(IBaseVault vault, address controller) public view returns (bool) {\n return vault.isOperator(controller, address(this));\n }\n\n /// @notice Gives the max approval to `to` for spending the given `asset` if not already approved.\n /// @dev Assumes that `type(uint256).max` is large enough to never have to increase the allowance again.\n function _approveMax(address asset, address spender) internal {\n if (IERC20(asset).allowance(address(this), spender) == 0) {\n SafeTransferLib.safeApprove(asset, spender, type(uint256).max);\n }\n }\n\n /// @notice Send native tokens to the gateway for transaction payment if it's not in a multicall.\n function _pay() internal {\n if (!gateway.isBatching()) {\n gateway.payTransaction{value: msg.value}(msg.sender);\n }\n }\n\n /// @notice Ensures msg.sender is either the controller, or can permissionlessly claim\n /// on behalf of the controller.\n function _canClaim(IBaseVault vault, address receiver, address controller) internal view {\n require(controller == msg.sender || (controller == receiver && isEnabled(vault, controller)), InvalidSender());\n }\n}\n" + }, + "src/vaults/factories/AsyncVaultFactory.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nimport {AsyncVault} from \"src/vaults/AsyncVault.sol\";\nimport {IVaultFactory} from \"src/vaults/interfaces/factories/IVaultFactory.sol\";\nimport {IPoolEscrowProvider} from \"src/vaults/interfaces/factories/IPoolEscrowFactory.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\nimport {IAsyncRequestManager} from \"src/vaults/interfaces/investments/IAsyncRequestManager.sol\";\nimport {IBaseVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\n\n/// @title ERC7540 Vault Factory\n/// @dev Utility for deploying new vault contracts\ncontract AsyncVaultFactory is Auth, IVaultFactory {\n address public immutable root;\n IAsyncRequestManager public immutable asyncRequestManager;\n\n constructor(address root_, IAsyncRequestManager asyncRequestManager_, address deployer) Auth(deployer) {\n root = root_;\n asyncRequestManager = asyncRequestManager_;\n }\n\n /// @inheritdoc IVaultFactory\n function newVault(\n PoolId poolId,\n ShareClassId scId,\n address asset,\n uint256 tokenId,\n IShareToken token,\n address[] calldata wards_\n ) public auth returns (IBaseVault) {\n require(tokenId == 0, UnsupportedTokenId());\n AsyncVault vault = new AsyncVault(poolId, scId, asset, token, root, asyncRequestManager);\n\n vault.rely(root);\n vault.rely(address(asyncRequestManager));\n uint256 wardsCount = wards_.length;\n for (uint256 i; i < wardsCount; i++) {\n vault.rely(wards_[i]);\n }\n\n vault.deny(address(this));\n return vault;\n }\n}\n" + }, + "src/vaults/factories/PoolEscrowFactory.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\n\nimport {IPoolEscrowProvider, IPoolEscrowFactory} from \"src/vaults/interfaces/factories/IPoolEscrowFactory.sol\";\nimport {IPoolEscrow} from \"src/vaults/interfaces/IEscrow.sol\";\nimport {PoolEscrow} from \"src/vaults/Escrow.sol\";\n\ncontract PoolEscrowFactory is Auth, IPoolEscrowFactory {\n address public immutable root;\n\n address public gateway;\n address public poolManager;\n address public balanceSheet;\n address public asyncRequestManager;\n\n constructor(address root_, address deployer) Auth(deployer) {\n root = root_;\n }\n\n /// @inheritdoc IPoolEscrowFactory\n function file(bytes32 what, address data) external auth {\n if (what == \"poolManager\") poolManager = data;\n else if (what == \"gateway\") gateway = data;\n else if (what == \"balanceSheet\") balanceSheet = data;\n else if (what == \"asyncRequestManager\") asyncRequestManager = data;\n else revert FileUnrecognizedParam();\n emit File(what, data);\n }\n\n /// @inheritdoc IPoolEscrowFactory\n function newEscrow(PoolId poolId) public auth returns (IPoolEscrow) {\n PoolEscrow escrow_ = new PoolEscrow{salt: bytes32(uint256(poolId.raw()))}(poolId, address(this));\n\n escrow_.rely(root);\n escrow_.rely(gateway);\n escrow_.rely(poolManager);\n escrow_.rely(balanceSheet);\n escrow_.rely(asyncRequestManager);\n\n escrow_.deny(address(this));\n\n emit DeployPoolEscrow(poolId, address(escrow_));\n return IPoolEscrow(escrow_);\n }\n\n /// @inheritdoc IPoolEscrowProvider\n function escrow(PoolId poolId) external view returns (IPoolEscrow) {\n bytes32 salt = bytes32(uint256(poolId.raw()));\n bytes32 hash = keccak256(\n abi.encodePacked(\n bytes1(0xff),\n address(this),\n salt,\n keccak256(abi.encodePacked(type(PoolEscrow).creationCode, abi.encode(poolId, address(this))))\n )\n );\n\n return IPoolEscrow(address(uint160(uint256(hash))));\n }\n}\n" + }, + "src/vaults/factories/SyncDepositVaultFactory.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nimport {SyncDepositVault} from \"src/vaults/SyncDepositVault.sol\";\nimport {IVaultFactory} from \"src/vaults/interfaces/factories/IVaultFactory.sol\";\nimport {IAsyncRedeemManager} from \"src/vaults/interfaces/investments/IAsyncRedeemManager.sol\";\nimport {ISyncDepositManager} from \"src/vaults/interfaces/investments/ISyncDepositManager.sol\";\nimport {IPoolEscrowProvider} from \"src/vaults/interfaces/factories/IPoolEscrowFactory.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\nimport {IBaseVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\n\n/// @title Sync Vault Factory\n/// @dev Utility for deploying new vault contracts\ncontract SyncDepositVaultFactory is Auth, IVaultFactory {\n address public immutable root;\n ISyncDepositManager public immutable syncDepositManager;\n IAsyncRedeemManager public immutable asyncRedeemManager;\n\n constructor(\n address root_,\n ISyncDepositManager syncDepositManager_,\n IAsyncRedeemManager asyncRedeemManager_,\n address deployer\n ) Auth(deployer) {\n root = root_;\n syncDepositManager = syncDepositManager_;\n asyncRedeemManager = asyncRedeemManager_;\n }\n\n /// @inheritdoc IVaultFactory\n function newVault(\n PoolId poolId,\n ShareClassId scId,\n address asset,\n uint256 tokenId,\n IShareToken token,\n address[] calldata wards_\n ) public auth returns (IBaseVault) {\n require(tokenId == 0, UnsupportedTokenId());\n SyncDepositVault vault =\n new SyncDepositVault(poolId, scId, asset, token, root, syncDepositManager, asyncRedeemManager);\n\n vault.rely(root);\n vault.rely(address(syncDepositManager));\n vault.rely(address(asyncRedeemManager));\n\n uint256 wardsCount = wards_.length;\n for (uint256 i; i < wardsCount; i++) {\n vault.rely(wards_[i]);\n }\n\n vault.deny(address(this));\n return vault;\n }\n}\n" + }, + "src/vaults/factories/TokenFactory.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\n\nimport {ShareToken} from \"src/vaults/token/ShareToken.sol\";\nimport {ITokenFactory} from \"src/vaults/interfaces/factories/ITokenFactory.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\n\n/// @title Share Token Factory\n/// @dev Utility for deploying new share class token contracts\n/// Ensures the addresses are deployed at a deterministic address\n/// based on the pool id and share class id.\ncontract TokenFactory is Auth, ITokenFactory {\n address public immutable root;\n\n constructor(address _root, address deployer) Auth(deployer) {\n root = _root;\n }\n\n /// @inheritdoc ITokenFactory\n function newToken(\n string memory name,\n string memory symbol,\n uint8 decimals,\n bytes32 salt,\n address[] calldata tokenWards\n ) public auth returns (IShareToken) {\n ShareToken token = new ShareToken{salt: salt}(decimals);\n\n token.file(\"name\", name);\n token.file(\"symbol\", symbol);\n\n token.rely(root);\n uint256 wardsCount = tokenWards.length;\n for (uint256 i; i < wardsCount; i++) {\n token.rely(tokenWards[i]);\n }\n token.deny(address(this));\n\n return token;\n }\n\n /// @inheritdoc ITokenFactory\n function getAddress(uint8 decimals, bytes32 salt) external view returns (address) {\n bytes32 hash = keccak256(\n abi.encodePacked(\n bytes1(0xff),\n address(this),\n salt,\n keccak256(abi.encodePacked(type(ShareToken).creationCode, abi.encode(decimals)))\n )\n );\n\n return address(uint160(uint256(hash)));\n }\n}\n" + }, + "src/vaults/interfaces/IBalanceSheet.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {D18, d18} from \"src/misc/types/D18.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\n\nstruct QueueAmount {\n // Issuances of shares / deposits of assets\n uint128 increase;\n // Revocations of shares / withdraws of assets\n uint128 decrease;\n}\n\ninterface IBalanceSheet {\n // --- Events ---\n event File(bytes32 indexed what, address data);\n event UpdateManager(PoolId indexed poolId, address who, bool canManage);\n event Withdraw(\n PoolId indexed poolId,\n ShareClassId indexed scId,\n address asset,\n uint256 tokenId,\n address receiver,\n uint128 amount,\n D18 pricePoolPerAsset\n );\n event Deposit(\n PoolId indexed poolId,\n ShareClassId indexed scId,\n address asset,\n uint256 tokenId,\n address provider,\n uint128 amount,\n D18 pricePoolPerAsset\n );\n event Issue(PoolId indexed poolId, ShareClassId indexed scId, address to, D18 pricePoolPerShare, uint128 shares);\n event Revoke(PoolId indexed poolId, ShareClassId indexed scId, address from, D18 pricePoolPerShare, uint128 shares);\n\n // --- Errors ---\n error FileUnrecognizedParam();\n error CannotTransferFromEndorsedContract();\n\n /// @notice Overloaded increase with asset transfer\n function deposit(PoolId poolId, ShareClassId scId, address asset, uint256 tokenId, address provider, uint128 amount)\n external;\n\n function noteDeposit(\n PoolId poolId,\n ShareClassId scId,\n address asset,\n uint256 tokenId,\n address provider,\n uint128 amount\n ) external;\n\n function withdraw(\n PoolId poolId,\n ShareClassId scId,\n address asset,\n uint256 tokenId,\n address receiver,\n uint128 amount\n ) external;\n\n function issue(PoolId poolId, ShareClassId scId, address to, uint128 shares) external;\n\n function revoke(PoolId poolId, ShareClassId scId, address from, uint128 shares) external;\n\n function noteRevoke(PoolId poolId, ShareClassId scId, address from, uint128 shares) external;\n\n function transferSharesFrom(PoolId poolId, ShareClassId scId, address from, address to, uint256 amount) external;\n\n function overridePricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId, D18 value) external;\n\n function overridePricePoolPerShare(PoolId poolId, ShareClassId scId, D18 value) external;\n}\n" + }, + "src/vaults/interfaces/IBaseVaults.sol": { + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.5.0;\n\nenum VaultKind {\n /// @dev Refers to AsyncVault\n Async,\n /// @dev not yet supported\n Sync,\n /// @dev Refers to SyncDepositVault\n SyncDepositAsyncRedeem\n}\n\nimport {IERC7575, IERC165} from \"src/misc/interfaces/IERC7575.sol\";\nimport {\n IERC7540Operator,\n IERC7714,\n IERC7741,\n IERC7540Redeem,\n IERC7887Redeem,\n IERC7887Deposit,\n IERC7540Deposit\n} from \"src/misc/interfaces/IERC7540.sol\";\nimport {IRecoverable} from \"src/misc/interfaces/IRecoverable.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nimport {IBaseRequestManager} from \"src/vaults/interfaces/investments/IBaseRequestManager.sol\";\nimport {IAsyncRedeemManager} from \"src/vaults/interfaces/investments/IAsyncRedeemManager.sol\";\n\n/// @notice Interface for the all vault contracts\n/// @dev Must be implemented by all vaults\ninterface IBaseVault is IERC7540Operator, IERC7741, IERC7714, IERC7575, IRecoverable {\n error FileUnrecognizedParam();\n error NotEndorsed();\n error CannotSetSelfAsOperator();\n error ExpiredAuthorization();\n error AlreadyUsedAuthorization();\n error InvalidAuthorization();\n error InvalidController();\n error InsufficientBalance();\n error RequestRedeemFailed();\n error TransferFromFailed();\n\n event File(bytes32 indexed what, address data);\n\n /// @notice Identifier of the Centrifuge pool\n function poolId() external view returns (PoolId);\n\n /// @notice Identifier of the share class of the Centrifuge pool\n function scId() external view returns (ShareClassId);\n\n /// @notice Set msg.sender as operator of owner, to `approved` status\n /// @dev MUST be called by endorsed sender\n function setEndorsedOperator(address owner, bool approved) external;\n\n /// @notice Returns the base investment manager contract handling the vault.\n /// @dev This naming MUST NOT change due to requirements of legacy vaults (v2)\n /// @return IBaseRequestManager The address of the manager contract that is between vault and gateway\n function manager() external view returns (IBaseRequestManager);\n\n /// @notice Checks whether the vault is partially (a)synchronous.\n ///\n /// @return vaultKind_ The kind of the vault\n function vaultKind() external view returns (VaultKind vaultKind_);\n}\n\n/**\n * @title IAsyncRedeemVault\n * @dev This is the specific set of interfaces used by the Centrifuge implementation of ERC7540,\n * as a fully asynchronous Vault, with cancellation support, and authorize operator signature support.\n */\ninterface IAsyncRedeemVault is IERC7540Redeem, IERC7887Redeem, IBaseVault {\n event RedeemClaimable(address indexed controller, uint256 indexed requestId, uint256 assets, uint256 shares);\n event CancelRedeemClaimable(address indexed controller, uint256 indexed requestId, uint256 shares);\n\n /// @notice Callback when a redeem Request is triggered externally;\n function onRedeemRequest(address controller, address owner, uint256 shares) external;\n\n /// @notice Callback when a redeem Request becomes claimable\n function onRedeemClaimable(address owner, uint256 assets, uint256 shares) external;\n\n /// @notice Callback when a claim redeem Request becomes claimable\n function onCancelRedeemClaimable(address owner, uint256 shares) external;\n\n /// @notice Retrieve the asynchronous redeem manager\n function asyncRedeemManager() external view returns (IAsyncRedeemManager);\n}\n\ninterface IAsyncVault is IERC7540Deposit, IERC7887Deposit, IAsyncRedeemVault {\n event DepositClaimable(address indexed controller, uint256 indexed requestId, uint256 assets, uint256 shares);\n event CancelDepositClaimable(address indexed controller, uint256 indexed requestId, uint256 assets);\n\n error InvalidOwner();\n error RequestDepositFailed();\n\n /// @notice Callback when a deposit Request becomes claimable\n function onDepositClaimable(address owner, uint256 assets, uint256 shares) external;\n\n /// @notice Callback when a claim deposit Request becomes claimable\n function onCancelDepositClaimable(address owner, uint256 assets) external;\n}\n" + }, + "src/vaults/interfaces/IEscrow.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IRecoverable} from \"src/misc/Recoverable.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\n/// @title Escrow for holding assets\ninterface IEscrow {\n // --- Events ---\n /// @notice Emitted when an authTransferTo is made\n /// @dev Needed as allowances increase attack surface\n event AuthTransferTo(address indexed asset, uint256 indexed tokenId, address reciver, uint256 value);\n\n /// @notice Emitted when the escrow has insufficient balance for an action - virtual or actual balance\n error InsufficientBalance(address asset, uint256 tokenId, uint256 value, uint256 balance);\n\n /// @notice\n function authTransferTo(address asset, uint256 tokenId, address receiver, uint256 value) external;\n\n /// @notice\n function authTransferTo(address asset, address receiver, uint256 value) external;\n}\n\nstruct Holding {\n uint128 total;\n uint128 reserved;\n}\n\n/// @title PerPoolEscrow separating funds by pool and share class\ninterface IPoolEscrow is IEscrow, IRecoverable {\n // --- Events ---\n /// @notice Emitted when a deposit is made\n /// @param asset The address of the deposited asset\n /// @param tokenId The id of the asset - 0 for ERC20\n /// @param poolId The id of the pool\n /// @param scId The id of the share class\n /// @param value The amount deposited\n event Deposit(\n address indexed asset, uint256 indexed tokenId, PoolId indexed poolId, ShareClassId scId, uint128 value\n );\n\n /// @notice Emitted when an amount is reserved\n /// @param asset The address of the reserved asset\n /// @param tokenId The id of the asset - 0 for ERC20\n /// @param poolId The id of the pool\n /// @param scId The id of the share class\n /// @param value The delta amount reserved\n /// @param value The new absolute amount reserved\n event IncreaseReserve(\n address indexed asset,\n uint256 indexed tokenId,\n PoolId indexed poolId,\n ShareClassId scId,\n uint256 delta,\n uint128 value\n );\n\n /// @notice Emitted when an amount is unreserved\n /// @param asset The address of the reserved asset\n /// @param tokenId The id of the asset - 0 for ERC20\n /// @param poolId The id of the pool\n /// @param scId The id of the share class\n /// @param value The delta amount unreserved\n /// @param value The new absolute amount reserved\n event DecreaseReserve(\n address indexed asset,\n uint256 indexed tokenId,\n PoolId indexed poolId,\n ShareClassId scId,\n uint256 delta,\n uint128 value\n );\n\n /// @notice Emitted when a withdraw is made\n /// @param asset The address of the withdrawn asset\n /// @param tokenId The id of the asset - 0 for ERC20\n /// @param poolId The id of the pool\n /// @param scId The id of the share class\n /// @param value The amount withdrawn\n event Withdraw(\n address indexed asset, uint256 indexed tokenId, PoolId indexed poolId, ShareClassId scId, uint128 value\n );\n\n // --- Errors ---\n /// @notice Dispatched when the balance of the escrow did not increase sufficiently\n error InsufficientDeposit();\n\n /// @notice Dispatched when the outstanding reserved amount is insufficient for the decrease\n error InsufficientReservedAmount();\n\n // --- Functions ---\n /// @notice Deposits `value` of `asset` in underlying `poolId` and given `scId`\n ///\n /// @dev NOTE: Must ensure balance sufficiency, i.e. that the depositing amount does not exceed the balance of\n /// escrow\n ///\n /// @param scId The id of the share class\n /// @param asset The address of the asset to be deposited\n /// @param tokenId The id of the asset - 0 for ERC20\n /// @param value The amount to deposit\n function deposit(ShareClassId scId, address asset, uint256 tokenId, uint128 value) external;\n\n /// @notice Withdraws `value` of `asset` in underlying `poolId` and given `scId`\n /// @dev MUST ensure that reserved amounts are not withdrawn\n /// @param scId The id of the share class\n /// @param asset The address of the asset to be withdrawn\n /// @param tokenId The id of the asset - 0 for ERC20\n /// @param value The amount to withdraw\n function withdraw(ShareClassId scId, address asset, uint256 tokenId, uint128 value) external;\n\n /// @notice Increases the reserved amount of `value` for `asset` in underlying `poolId` and given `scId`\n /// @dev MUST prevent the reserved amount from being withdrawn\n /// @param scId The id of the share class\n /// @param asset The address of the asset to be reserved\n /// @param tokenId The id of the asset - 0 for ERC20\n /// @param value The amount to reserve\n function reserveIncrease(ShareClassId scId, address asset, uint256 tokenId, uint128 value) external;\n\n /// @notice Decreases the reserved amount of `value` for `asset` in underlying `poolId` and given `scId`\n /// @dev MUST fail if `value` is greater than the current reserved amount\n /// @param scId The id of the share class\n /// @param asset The address of the asset to be reserved\n /// @param tokenId The id of the asset - 0 for ERC20\n /// @param value The amount to decrease\n function reserveDecrease(ShareClassId scId, address asset, uint256 tokenId, uint128 value) external;\n\n /// @notice Provides the available balance of `asset` in underlying `poolId` and given `scId`\n /// @dev MUST return the balance minus the reserved amount\n /// @param scId The id of the share class\n /// @param asset The address of the asset to be checked\n /// @param tokenId The id of the asset - 0 for ERC20\n /// @return The available balance\n function availableBalanceOf(ShareClassId scId, address asset, uint256 tokenId) external view returns (uint128);\n}\n" + }, + "src/vaults/interfaces/IPoolManager.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {D18, d18} from \"src/misc/types/D18.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\n\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\nimport {IVaultFactory} from \"src/vaults/interfaces/factories/IVaultFactory.sol\";\nimport {IBaseVault, VaultKind} from \"src/vaults/interfaces/IBaseVaults.sol\";\n\n/// @dev Centrifuge pools\nstruct Pool {\n uint256 createdAt;\n mapping(ShareClassId scId => ShareClassDetails) shareClasses;\n}\n\n/// @dev Each Centrifuge pool is associated to 1 or more shar classes\nstruct ShareClassDetails {\n IShareToken shareToken;\n /// @dev Each share class has an individual price per share class unit in pool denomination (POOL_UNIT/SHARE_UNIT)\n Price pricePoolPerShare;\n /// @dev Each share class can have multiple vaults deployed,\n /// multiple vaults can be linked to the same asset.\n /// A vault in this storage DOES NOT mean the vault can be used\n mapping(address asset => mapping(uint256 tokenId => IBaseVault[])) vaults;\n /// @dev For each share class, we store the price per pool unit in asset denomination (POOL_UNIT/ASSET_UNIT)\n mapping(address asset => mapping(uint256 tokenId => Price)) pricePoolPerAsset;\n}\n\n/// @dev Price struct that contains a price, the timestamp at which it was computed and the max age of the price.\nstruct Price {\n uint128 price;\n uint64 computedAt;\n uint64 maxAge;\n}\n\n/// @dev Checks if a price is valid. Returns false if price is 0 or computedAt is 0. Otherwise checks for block\n/// timestamp <= computedAt + maxAge\nfunction isValid(Price memory price) view returns (bool) {\n if (price.computedAt != 0 && price.price != 0) {\n return block.timestamp <= price.validUntil();\n } else {\n return false;\n }\n}\n\n/// @dev Computes the timestamp until the price is valid. Saturates at uint64.MAX.\nfunction validUntil(Price memory price) pure returns (uint64) {\n unchecked {\n uint64 validUntil_ = price.computedAt + price.maxAge;\n if (validUntil_ < price.computedAt) {\n return type(uint64).max;\n }\n return validUntil_;\n }\n}\n\n/// @dev Retrieves the price as an D18 from the struct\nfunction asPrice(Price memory price) pure returns (D18) {\n return d18(price.price);\n}\n\nusing {isValid, asPrice, validUntil} for Price global;\n\nstruct VaultDetails {\n /// @dev AssetId of the asset\n AssetId assetId;\n /// @dev Address of the asset\n address asset;\n /// @dev TokenId of the asset - zero if asset is ERC20, non-zero if asset is ERC6909\n uint256 tokenId;\n /// @dev Whether this wrapper conforms to the IERC20Wrapper interface\n bool isWrapper;\n /// @dev Whether the vault is linked to a share class atm\n bool isLinked;\n}\n\nstruct AssetIdKey {\n /// @dev The address of the asset\n address asset;\n /// @dev The ERC6909 token id or 0, if the underlying asset is an ERC20\n uint256 tokenId;\n}\n\ninterface IPoolManager {\n event File(bytes32 indexed what, address data);\n event RegisterAsset(\n AssetId indexed assetId,\n address indexed asset,\n uint256 indexed tokenId,\n string name,\n string symbol,\n uint8 decimals\n );\n event File(bytes32 indexed what, address factory, bool status);\n event AddPool(PoolId indexed poolId);\n event AddShareClass(PoolId indexed poolId, ShareClassId indexed scId, IShareToken token);\n event DeployVault(\n PoolId indexed poolId,\n ShareClassId indexed scId,\n address indexed asset,\n uint256 tokenId,\n IVaultFactory factory,\n IBaseVault vault,\n VaultKind kind\n );\n event PriceUpdate(\n PoolId indexed poolId,\n ShareClassId indexed scId,\n address indexed asset,\n uint256 tokenId,\n uint256 price,\n uint64 computedAt\n );\n event PriceUpdate(PoolId indexed poolId, ShareClassId indexed scId, uint256 price, uint64 computedAt);\n event TransferShares(\n uint16 centrifugeId,\n PoolId indexed poolId,\n ShareClassId indexed scId,\n address indexed sender,\n bytes32 destinationAddress,\n uint128 amount\n );\n event UpdateContract(PoolId indexed poolId, ShareClassId indexed scId, address target, bytes payload);\n event LinkVault(\n PoolId indexed poolId, ShareClassId indexed scId, address indexed asset, uint256 tokenId, IBaseVault vault\n );\n event UnlinkVault(\n PoolId indexed poolId, ShareClassId indexed scId, address indexed asset, uint256 tokenId, IBaseVault vault\n );\n event UpdateMaxSharePriceAge(PoolId indexed poolId, ShareClassId indexed scId, uint64 maxPriceAge);\n event UpdateMaxAssetPriceAge(\n PoolId indexed poolId, ShareClassId indexed scId, address indexed asset, uint256 tokenId, uint64 maxPriceAge\n );\n\n error FileUnrecognizedParam();\n error TooFewDecimals();\n error TooManyDecimals();\n error PoolAlreadyAdded();\n error InvalidPool();\n error ShareClassAlreadyRegistered();\n error InvalidHook();\n error OldMetadata();\n error CannotSetOlderPrice();\n error OldHook();\n error UnknownVault();\n error UnknownAsset();\n error MalformedVaultUpdateMessage();\n error UnknownToken();\n error InvalidFactory();\n error InvalidPrice();\n error AssetMissingDecimals();\n error ShareTokenDoesNotExist();\n error LocalTransferNotAllowed();\n error CrossChainTransferNotAllowed();\n error ShareTokenTransferFailed();\n error TransferFromFailed();\n\n /// @notice Returns the asset address and tokenId associated with a given asset id.\n /// @dev Reverts if asset id does not exist\n ///\n /// @param assetId The underlying internal uint128 assetId.\n /// @return asset The address of the asset linked to the given asset id.\n /// @return tokenId The token id corresponding to the asset, i.e. zero if ERC20 or non-zero if ERC6909.\n function idToAsset(AssetId assetId) external view returns (address asset, uint256 tokenId);\n\n /// @notice Returns assetId given the asset address and tokenId.\n /// @dev Reverts if asset id does not exist\n ///\n /// @param asset The address of the asset linked to the given asset id.\n /// @param tokenId The token id corresponding to the asset, i.e. zero if ERC20 or non-zero if ERC6909.\n /// @return assetId The underlying internal uint128 assetId.\n function assetToId(address asset, uint256 tokenId) external view returns (AssetId assetId);\n\n /// @notice Updates a contract parameter\n /// @param what Accepts a bytes32 representation of 'gateway', 'investmentManager', 'tokenFactory',\n /// 'vaultFactory', or 'gasService'\n function file(bytes32 what, address data) external;\n\n /// @notice Updates a contract parameter\n /// @param what Accepts a bytes32 representation of 'vaultFactory'\n function file(bytes32 what, address factory, bool status) external;\n\n /// @notice transfers share class tokens to a cross-chain recipient address\n /// @dev To transfer to evm chains, pad a 20 byte evm address with 12 bytes of 0\n /// @param centrifugeId The destination chain id\n /// @param poolId The centrifuge pool id\n /// @param scId The share class id\n /// @param receiver A bytes32 representation of the receiver address\n /// @param amount The amount of tokens to transfer\n function transferShares(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bytes32 receiver, uint128 amount)\n external\n payable;\n\n /// @notice Registers an ERC-20 or ERC-6909 asset in another chain.\n /// @dev `decimals()` MUST return a `uint8` value between 2 and 18.\n /// @dev `name()` and `symbol()` MAY return no values.\n ///\n /// @param centrifugeId The centrifuge id of chain to where the shares are transferred\n /// @param asset The address of the asset to be registered\n /// @param tokenId The token id corresponding to the asset, i.e. zero if ERC20 or non-zero if ERC6909.\n /// @return assetId The underlying internal uint128 assetId.\n function registerAsset(uint16 centrifugeId, address asset, uint256 tokenId)\n external\n payable\n returns (AssetId assetId);\n\n /// @notice Deploys a new vault\n ///\n /// @param poolId The pool id\n /// @param scId The share class id\n /// @param assetId The asset id for which we want to deploy a vault\n /// @param factory The address of the corresponding vault factory\n /// @return address The address of the deployed vault\n function deployVault(PoolId poolId, ShareClassId scId, AssetId assetId, IVaultFactory factory)\n external\n returns (IBaseVault);\n\n /// @notice Links a deployed vault to the given pool, share class and asset.\n ///\n /// @param poolId The pool id\n /// @param scId The share class id\n /// @param assetId The asset id for which we want to deploy a vault\n /// @param vault The address of the deployed vault\n function linkVault(PoolId poolId, ShareClassId scId, AssetId assetId, IBaseVault vault) external;\n\n /// @notice Removes the link between a vault and the given pool, share class and asset.\n ///\n /// @param poolId The pool id\n /// @param scId The share class id\n /// @param assetId The asset id for which we want to deploy a vault\n /// @param vault The address of the deployed vault\n function unlinkVault(PoolId poolId, ShareClassId scId, AssetId assetId, IBaseVault vault) external;\n\n /// @notice Returns whether the given pool id is active\n function isPoolActive(PoolId poolId) external view returns (bool);\n\n /// @notice Returns the share class token for a given pool and share class id.\n /// @dev Reverts if share class does not exists\n ///\n /// @param poolId The pool id\n /// @param scId The share class id\n /// @return address The address of the share token\n function shareToken(PoolId poolId, ShareClassId scId) external view returns (IShareToken);\n\n /// @notice Function to get the details of a vault\n /// @dev Reverts if vault does not exist\n ///\n /// @param vault The address of the vault to be checked for\n /// @return details The details of the vault including the underlying asset address, token id, asset id\n function vaultDetails(IBaseVault vault) external view returns (VaultDetails memory details);\n\n /// @notice Checks whether a given asset-vault pair is eligible for investing into a share class of a pool\n ///\n /// @param poolId The pool id\n /// @param scId The share class id\n /// @param asset The address of the asset\n /// @param vault The address of the vault\n /// @return bool Whether vault is to a share class\n function isLinked(PoolId poolId, ShareClassId scId, address asset, IBaseVault vault) external view returns (bool);\n\n /// @notice Returns the price per share for a given pool, share class, asset, and asset id. The provided price is\n /// defined as ASSET_UNIT/SHARE_UNIT.\n /// @dev Conditionally checks if price is valid.\n ///\n /// @dev NOTE: Should never be used for calculating amounts due to precision loss. Instead, please refer to\n /// conversion relying on pricePoolPerShare and pricePoolPerAsset. See PricingLib for more information.\n ///\n /// @param poolId The pool id\n /// @param scId The share class id\n /// @param assetId The asset id for which we want to know the ASSET_UNIT/SHARE_UNIT price\n /// @param checkValidity Whether to check if the price is valid\n /// @return price The asset price per share\n function priceAssetPerShare(PoolId poolId, ShareClassId scId, AssetId assetId, bool checkValidity)\n external\n view\n returns (D18 price);\n\n /// @notice Returns the price per share for a given pool and share class. The Provided price is defined as\n /// POOL_UNIT/SHARE_UNIT.\n /// @dev Conditionally checks if price is valid.\n ///\n /// @param poolId The pool id\n /// @param scId The share class id\n /// @param checkValidity Whether to check if the price is valid\n /// @return price The pool price per share\n function pricePoolPerShare(PoolId poolId, ShareClassId scId, bool checkValidity)\n external\n view\n returns (D18 price);\n\n /// @notice Returns the price per asset for a given pool, share class and the underlying asset id. The Provided\n /// price is defined as POOL_UNIT/ASSET_UNIT.\n /// @dev Conditionally checks if price is valid.\n ///\n /// @param poolId The pool id\n /// @param scId The share class id\n /// @param assetId The asset id for which we want to know the POOL_UNIT/ASSET_UNIT.\n /// @param checkValidity Whether to check if the price is valid\n /// @return price The pool price per asset unit\n function pricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId, bool checkValidity)\n external\n view\n returns (D18 price);\n\n /// @notice Returns the both prices per pool for a given pool, share class and the underlying asset id. The Provided\n /// prices is defined as POOL_UNIT/ASSET_UNIT and POOL_UNIT/SHARE_UNIT.\n /// @dev Conditionally checks if prices are valid.\n ///\n /// @param poolId The pool id\n /// @param scId The share class id\n /// @param assetId The asset id for which we want to know pool price per asset\n /// @param checkValidity Whether to check if the prices are valid\n /// @return pricePoolPerAsset The pool price per asset unit, i.e. POOL_UNIT/ASSET_UNIT\n /// @return pricePoolPerShare The pool price per share unit, i.e. POOL_UNIT/SHARE_UNIT\n function pricesPoolPer(PoolId poolId, ShareClassId scId, AssetId assetId, bool checkValidity)\n external\n view\n returns (D18 pricePoolPerAsset, D18 pricePoolPerShare);\n\n /// @notice Returns the age related markers for a share class price\n ///\n /// @param poolId The pool id\n /// @param scId The share class id\n /// @return computedAt The timestamp when this price was computed\n /// @return maxAge The maximum age this price is allowed to have\n /// @return validUntil The timestamp until this price is valid\n function markersPricePoolPerShare(PoolId poolId, ShareClassId scId)\n external\n view\n returns (uint64 computedAt, uint64 maxAge, uint64 validUntil);\n\n /// @notice Returns the age related markers for an asset price\n ///\n /// @param poolId The pool id\n /// @param scId The share class id\n /// @param assetId The asset id for which we want to know pool price per asset\n /// @return computedAt The timestamp when this price was computed\n /// @return maxAge The maximum age this price is allowed to have\n /// @return validUntil The timestamp until this price is valid\n function markersPricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId)\n external\n view\n returns (uint64 computedAt, uint64 maxAge, uint64 validUntil);\n}\n" + }, + "src/vaults/interfaces/IUpdateContract.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\n\ninterface IUpdateContract {\n error UnknownUpdateContractType();\n\n /// @notice Triggers an update on the target contract.\n /// @param poolId The centrifuge pool id\n /// @param scId The share class id\n /// @param payload The payload to be processed by the target address\n function update(PoolId poolId, ShareClassId scId, bytes calldata payload) external;\n}\n" + }, + "src/vaults/interfaces/IVaultRouter.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IMulticall} from \"src/misc/interfaces/IMulticall.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {IBaseVault, IAsyncVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\nimport {BaseSyncDepositVault} from \"src/vaults/BaseVaults.sol\";\n\ninterface IVaultRouter is IMulticall {\n // --- Events ---\n event LockDepositRequest(\n IBaseVault indexed vault, address indexed controller, address indexed owner, address sender, uint256 amount\n );\n event UnlockDepositRequest(IBaseVault indexed vault, address indexed controller, address indexed receiver);\n event ExecuteLockedDepositRequest(IBaseVault indexed vault, address indexed controller, address sender);\n\n error InvalidOwner();\n error NoLockedBalance();\n error NoLockedRequest();\n error ZeroBalance();\n error WrapFailed();\n error UnwrapFailed();\n error InvalidSender();\n error NonSyncDepositVault();\n error NonAsyncVault();\n\n /// @notice Check how much of the `vault`'s asset is locked for the current `controller`.\n /// @dev This is a getter method\n function lockedRequests(address controller, IBaseVault vault) external view returns (uint256 amount);\n\n // --- Manage permissionless claiming ---\n /// @notice Enable permissionless claiming\n /// @dev After this is called, anyone can claim tokens to msg.sender.\n /// Even any requests submitted directly to the vault (not through the VaultRouter) will be\n /// permissionlessly claimable through the VaultRouter, until `disable()` is called.\n function enable(IBaseVault vault) external payable;\n\n /// @notice Disable permissionless claiming\n function disable(IBaseVault vault) external payable;\n\n // --- Deposit ---\n /// @notice Check `IERC7540Deposit.requestDeposit`.\n /// @dev This adds a mandatory prepayment for all the costs that will incur during the transaction.\n /// The caller must call `VaultRouter.estimate` to get estimates how much the deposit will cost.\n ///\n /// @param vault The vault to deposit into\n /// @param amount Check @param IERC7540Deposit.requestDeposit.assets\n /// @param controller Check @param IERC7540Deposit.requestDeposit.controller\n /// @param owner Check @param IERC7540Deposit.requestDeposit.owner\n function requestDeposit(IAsyncVault vault, uint256 amount, address controller, address owner) external payable;\n\n /// @notice Check `IERC4626.deposit`.\n /// @dev This adds a mandatory prepayment for all the costs that will incur during the transaction.\n /// The caller must call `VaultRouter.estimate` to get estimates how much the deposit will cost.\n ///\n /// @param vault The vault to deposit into\n /// @param assets Check @param IERC4626.deposit.assets\n /// @param receiver Check @param IERC4626.deposit.receiver\n /// @param owner User from which to transfer the assets, either msg.sender or the VaultRouter\n function deposit(BaseSyncDepositVault vault, uint256 assets, address receiver, address owner) external payable;\n\n /// @notice Locks `amount` of `vault`'s asset in an escrow before actually sending a deposit LockDepositRequest\n /// There are users that would like to interact with the protocol but don't have permissions yet. They can\n /// lock the funds they would like to deposit beforehand.\n /// Once permissions are granted, anyone can deposit on\n /// their behalf by calling `executeLockedDepositRequest`.\n ///\n /// Example: DAO with onchain governance, that wants to invest their treasury\n /// The process that doesn't include calling this method is as follows:\n ///\n /// 1. The DAO signs the legal agreements for the pool => no onchain action,\n /// but only after this the issuer can call update_member to add them as a whitelisted investor\n /// 2. Call `requestDeposit` to lock funds\n /// 3. After the pool has fulfilled their request, call `deposit` to claim their share class tokens\n ///\n ///\n /// With the new router function the steps are as follows:\n ///\n /// 1. DAO signs the legal agreement + calls `openLockDepositRequest` in 1 governance proposal\n ///\n /// 2. Issuer then gives them permissions, then calls `executeLockDepositFunds` for them,\n /// then fulfills the request, then calls `claimDeposit` for them\n ///\n /// @dev For initial interaction better use `openLockDepositRequest` which includes some of the message calls\n /// that the caller must do execute before calling `lockDepositRequest`\n ///\n /// @param vault The address of the vault to invest in\n /// @param amount Amount to invest\n /// @param controller Address of the owner of the position\n /// @param owner Where the funds to be deposited will be take from\n function lockDepositRequest(IBaseVault vault, uint256 amount, address controller, address owner) external payable;\n\n /// @notice Helper method to lock a deposit request, and enable permissionless claiming of that vault in 1 call.\n /// @dev It starts interaction with the vault by calling `open`.\n /// Vaults support assets that are wrapped one. When user calls this method\n /// and the vault's asset is a wrapped one, first the balance of the wrapped asset is checked.\n /// If balance >= `amount`, then this asset is used\n /// else amount is treat as an underlying asset one and it is wrapped.\n /// @param vault Address of the vault\n /// @param amount Amount to be deposited\n function enableLockDepositRequest(IBaseVault vault, uint256 amount) external payable;\n\n /// @notice Unlocks all deposited assets of the current caller for a given vault\n ///\n /// @param vault Address of the vault for which funds were locked\n /// @param receiver Address of the received of the unlocked funds\n function unlockDepositRequest(IBaseVault vault, address receiver) external payable;\n\n /// @notice After the controller is given permissions, anyone can call this method and\n /// actually request a deposit with the locked funds on the behalf of the `controller`\n /// @param vault The vault for which funds are locked\n /// @param controller Owner of the deposit position\n function executeLockedDepositRequest(IAsyncVault vault, address controller) external payable;\n\n /// @notice Check IERC7540Deposit.mint\n /// @param vault Address of the vault\n /// @param receiver Check IERC7540Deposit.mint.receiver\n /// @param controller Check IERC7540Deposit.mint.owner\n function claimDeposit(IAsyncVault vault, address receiver, address controller) external payable;\n\n // --- Redeem ---\n /// @notice Check `IERC7887Deposit.cancelDepositRequest`.\n /// @dev This adds a mandatory prepayment for all the costs that will incur during the transaction.\n /// The caller must call `VaultRouter.estimate` to get estimates how much the deposit will cost.\n ///\n /// @param vault The vault where the deposit was initiated\n function cancelDepositRequest(IAsyncVault vault) external payable;\n\n /// @notice Check IERC7887Deposit.claimCancelDepositRequest\n ///\n /// @param vault Address of the vault\n /// @param receiver Check IERC7887Deposit.claimCancelDepositRequest.receiver\n /// @param controller Check IERC7887Deposit.claimCancelDepositRequest.controller\n function claimCancelDepositRequest(IAsyncVault vault, address receiver, address controller) external payable;\n\n // --- Redeem ---\n /// @notice Check `IERC7540Redeem.requestRedeem`.\n /// @dev This adds a mandatory prepayment for all the costs that will incur during the transaction.\n /// The caller must call `VaultRouter.estimate` to get estimates how much the deposit will cost.\n ///\n /// @param vault The vault to deposit into\n /// @param amount Check @param IERC7540Redeem.requestRedeem.shares\n /// @param controller Check @param IERC7540Redeem.requestRedeem.controller\n /// @param owner Check @param IERC7540Redeem.requestRedeem.owner\n function requestRedeem(IAsyncVault vault, uint256 amount, address controller, address owner) external payable;\n\n /// @notice Check IERC7575.withdraw\n /// @dev If the underlying vault asset is a wrapped one,\n /// `VaultRouter.unwrap` is called and the unwrapped\n /// asset is sent to the receiver\n /// @param vault Address of the vault\n /// @param receiver Check IERC7575.withdraw.receiver\n /// @param controller Check IERC7575.withdraw.owner\n function claimRedeem(IBaseVault vault, address receiver, address controller) external payable;\n\n /// @notice Check `IERC7887Redeem.cancelRedeemRequest`.\n /// @dev This adds a mandatory prepayment for all the costs that will incur during the transaction.\n /// The caller must call `VaultRouter.estimate` to get estimates how much the deposit will cost.\n ///\n /// @param vault The vault where the deposit was initiated\n function cancelRedeemRequest(IAsyncVault vault) external payable;\n\n /// @notice Check IERC7887Redeem.claimableCancelRedeemRequest\n ///\n /// @param vault Address of the vault\n /// @param receiver Check IERC7887Redeem.claimCancelRedeemRequest.receiver\n /// @param controller Check IERC7887Redeem.claimCancelRedeemRequest.controller\n function claimCancelRedeemRequest(IAsyncVault vault, address receiver, address controller) external payable;\n\n // --- ERC20 permit ---\n /// @notice Check IERC20.permit\n function permit(address asset, address spender, uint256 assets, uint256 deadline, uint8 v, bytes32 r, bytes32 s)\n external\n payable;\n\n // --- ERC20 wrapping ---\n /// @notice There are vault which underlying asset is actuall a wrapped one.\n ///\n /// @param wrapper The address of the wrapper\n /// @param amount Amount to be wrapped\n /// @param receiver Receiver of the wrapped tokens\n /// @param owner The address from which `amount` is taken from\n function wrap(address wrapper, uint256 amount, address receiver, address owner) external payable;\n\n /// @notice There are vault which underlying asset is actuall a wrapped one.\n /// @dev Wrapped tokens need to be held by the VaultRouter to be unwrapped.\n /// @param wrapper The address of the wrapper\n /// @param amount Amount to be wrapped\n /// @param receiver Receiver of the unwrapped tokens\n function unwrap(address wrapper, uint256 amount, address receiver) external payable;\n\n // --- View Methods ---\n /// @notice Check IPoolManager.getVault\n function getVault(PoolId poolId, ShareClassId scId, address asset) external view returns (address);\n\n /// @notice Check IGateway.estimate\n /// If the destination and source chain ID are the same, this will always return 0.\n /// @param centrifugeId destination chain\n function estimate(uint16 centrifugeId, bytes calldata payload) external view returns (uint256 amount);\n\n /// @notice Called to check if `user` has permissions on `vault` to execute requests\n ///\n /// @param vault Address of the `vault` the `user` wants to operate on\n /// @param user Address of the `user` that will operates on the `vault`\n /// @return Whether `user` has permissions to operate on `vault`\n function hasPermissions(IBaseVault vault, address user) external view returns (bool);\n\n /// @notice Returns whether the controller has called `enable()` for the given `vault`\n function isEnabled(IBaseVault vault, address controller) external view returns (bool);\n}\n" + }, + "src/vaults/interfaces/factories/IPoolEscrowFactory.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\n\nimport {IPoolEscrow} from \"src/vaults/interfaces/IEscrow.sol\";\n\ninterface IPoolEscrowProvider {\n /// @notice Returns the deterministic address of an escrow contract based on a given pool id wrapped into the\n /// corresponding interface.\n ///\n /// @dev Does not check, whether the escrow was already deployed.\n function escrow(PoolId poolId) external view returns (IPoolEscrow);\n}\n\ninterface IPoolEscrowFactory is IPoolEscrowProvider {\n event DeployPoolEscrow(PoolId indexed poolId, address indexed escrow);\n event File(bytes32 what, address data);\n\n error FileUnrecognizedParam();\n error EscrowAlreadyDeployed();\n\n /// @notice Deploys new escrow and returns it.\n /// @dev All share classes of a pool are represented by the same escrow contract.\n ///\n /// @param poolId Id of the pool this escrow is deployed for\n /// @return IPoolEscrow The the newly deployed escrow contract\n function newEscrow(PoolId poolId) external returns (IPoolEscrow);\n\n /// @notice Updates contract parameters of type address.\n function file(bytes32 what, address data) external;\n}\n" + }, + "src/vaults/interfaces/factories/ITokenFactory.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\n\ninterface ITokenFactory {\n /// @notice Used to deploy new share class tokens.\n /// @dev In order to have the same address on different EVMs `salt` should be used\n /// during creationg process.\n /// @param name Name of the new token.\n /// @param symbol Symbol of the new token.\n /// @param decimals Decimals of the new token.\n /// @param salt Salt used for deterministic deployments.\n /// @param tokenWards Address which can call methods behind authorized only.\n function newToken(\n string memory name,\n string memory symbol,\n uint8 decimals,\n bytes32 salt,\n address[] calldata tokenWards\n ) external returns (IShareToken);\n\n /// @notice Returns the predicted address (using CREATE2)\n function getAddress(uint8 decimals, bytes32 salt) external view returns (address);\n}\n" + }, + "src/vaults/interfaces/factories/IVaultFactory.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\nimport {IPoolEscrow} from \"src/vaults/interfaces/IEscrow.sol\";\nimport {IBaseVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\n\ninterface IVaultFactory {\n error UnsupportedTokenId();\n\n /// @notice Deploys new vault for `poolId`, `scId` and `asset`.\n ///\n /// @param poolId Id of the pool. Id is one of the already supported pools.\n /// @param scId Id of the share class token. Id is one of the already supported share class tokens.\n /// @param asset Address of the underlying asset that is getting deposited inside the pool.\n /// @param asset Token id of the underlying asset that is getting deposited inside the pool. I.e. zero if asset\n /// corresponds to ERC20 or non-zero if asset corresponds to ERC6909.\n /// @param token Address of the share class token that is getting issues against the deposited asset.\n /// @param wards_ Address which can call methods behind authorized only.\n function newVault(\n PoolId poolId,\n ShareClassId scId,\n address asset,\n uint256 tokenId,\n IShareToken token,\n address[] calldata wards_\n ) external returns (IBaseVault);\n}\n" + }, + "src/vaults/interfaces/investments/IAsyncDepositManager.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IDepositManager} from \"src/vaults/interfaces/investments/IDepositManager.sol\";\nimport {IBaseVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\n\ninterface IAsyncDepositManager is IDepositManager {\n /// @notice Requests assets deposit. Vaults have to request investments from Centrifuge before\n /// shares can be minted. The deposit requests are added to the order book\n /// on the corresponding CP instance. Once the next epoch is executed on the corresponding CP instance,\n /// vaults can\n /// proceed with share payouts in case the order got fulfilled.\n /// @dev The assets required to fulfill the deposit request have to be locked and are transferred from the\n /// owner to the escrow, even though the share payout can only happen after epoch execution.\n /// The receiver becomes the owner of deposit request fulfillment.\n /// @param source Deprecated\n function requestDeposit(IBaseVault vault, uint256 assets, address receiver, address owner, address source)\n external\n returns (bool);\n\n /// @notice Requests the cancellation of a pending deposit request. Vaults have to request the\n /// cancellation of outstanding requests from Centrifuge before actual assets can be unlocked and\n /// transferred\n /// to the owner.\n /// While users have outstanding cancellation requests no new deposit requests can be submitted.\n /// Once the next epoch is executed on the corresponding CP instance, vaults can proceed with asset payouts\n /// if orders could be cancelled successfully.\n /// @dev The cancellation request might fail in case the pending deposit order already got fulfilled on\n /// Centrifuge.\n /// @param source Deprecated\n function cancelDepositRequest(IBaseVault vault, address owner, address source) external;\n\n /// @notice Processes owner's deposit request cancellation after the epoch has been executed on the corresponding CP\n /// instance and the\n /// deposit order cancellation has been successfully processed (partial fulfillment possible).\n /// Assets are transferred from the escrow to the receiver.\n /// @dev The assets required to fulfill the claim have already been reserved for the owner in escrow on\n /// fulfillCancelDepositRequest.\n function claimCancelDepositRequest(IBaseVault vault, address receiver, address owner)\n external\n returns (uint256 assets);\n\n /// @notice Indicates whether a user has pending deposit requests and returns the total deposit request asset\n /// request value.\n function pendingDepositRequest(IBaseVault vault, address user) external view returns (uint256 assets);\n\n /// @notice Indicates whether a user has pending deposit request cancellations.\n function pendingCancelDepositRequest(IBaseVault vault, address user) external view returns (bool isPending);\n\n /// @notice Indicates whether a user has claimable deposit request cancellation and returns the total claim\n /// value in assets.\n function claimableCancelDepositRequest(IBaseVault vault, address user) external view returns (uint256 assets);\n}\n" + }, + "src/vaults/interfaces/investments/IAsyncRedeemManager.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IRedeemManager} from \"src/vaults/interfaces/investments/IRedeemManager.sol\";\nimport {IBaseVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\n\ninterface IAsyncRedeemManager is IRedeemManager {\n /// @notice Requests share redemption. Vaults have to request redemptions\n /// from Centrifuge before actual asset payouts can be done. The redemption\n /// requests are added to the order book on the corresponding CP instance. Once the next epoch is\n /// executed on the corresponding CP instance, vaults can proceed with asset payouts\n /// in case the order got fulfilled.\n /// @dev The shares required to fulfill the redemption request have to be locked and are transferred from the\n /// owner to the escrow, even though the asset payout can only happen after epoch execution.\n /// The receiver becomes the owner of redeem request fulfillment.\n /// @param source Deprecated\n function requestRedeem(IBaseVault vault, uint256 shares, address receiver, address owner, address source)\n external\n returns (bool);\n\n /// @notice Requests the cancellation of an pending redeem request. Vaults have to request the\n /// cancellation of outstanding requests from Centrifuge before actual shares can be unlocked and\n /// transferred to the owner.\n /// While users have outstanding cancellation requests no new redeem requests can be submitted (exception:\n /// trigger through governance).\n /// Once the next epoch is executed on the corresponding CP instance, vaults can proceed with share payouts\n /// if the orders could be cancelled successfully.\n /// @dev The cancellation request might fail in case the pending redeem order already got fulfilled on\n /// Centrifuge.\n function cancelRedeemRequest(IBaseVault vault, address owner, address source) external;\n\n /// @notice Processes owner's redeem request cancellation after the epoch has been executed on the corresponding CP\n /// instance and the\n /// redeem order cancellation has been successfully processed (partial fulfillment possible).\n /// Shares are transferred from the escrow to the receiver.\n /// @dev The shares required to fulfill the claim have already been reserved for the owner in escrow on\n /// fulfillCancelRedeemRequest.\n /// Receiver has to pass all the share token restrictions in order to receive the shares.\n function claimCancelRedeemRequest(IBaseVault vault, address receiver, address owner)\n external\n returns (uint256 shares);\n\n /// @notice Indicates whether a user has pending redeem requests and returns the total share request value.\n function pendingRedeemRequest(IBaseVault vault, address user) external view returns (uint256 shares);\n\n /// @notice Indicates whether a user has pending redeem request cancellations.\n function pendingCancelRedeemRequest(IBaseVault vault, address user) external view returns (bool isPending);\n\n /// @notice Indicates whether a user has claimable redeem request cancellation and returns the total claim\n /// value in shares.\n function claimableCancelRedeemRequest(IBaseVault vault, address user) external view returns (uint256 shares);\n}\n" + }, + "src/vaults/interfaces/investments/IAsyncRequestManager.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IRequestManagerGatewayHandler} from \"src/common/interfaces/IGatewayHandlers.sol\";\n\nimport {IAsyncDepositManager} from \"src/vaults/interfaces/investments/IAsyncDepositManager.sol\";\nimport {IAsyncRedeemManager} from \"src/vaults/interfaces/investments/IAsyncRedeemManager.sol\";\nimport {IBaseVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\n\n/// @dev Vault requests and deposit/redeem bookkeeping per user\nstruct AsyncInvestmentState {\n /// @dev Shares that can be claimed using `mint()`\n uint128 maxMint;\n /// @dev Assets that can be claimed using `withdraw()`\n uint128 maxWithdraw;\n /// @dev Weighted average price of deposits, used to convert maxMint to maxDeposit\n /// @dev Represents priceAssetPerShare, i.e. ASSET_UNIT/SHARE_UNIT\n uint256 depositPrice;\n /// @dev Weighted average price of redemptions, used to convert maxWithdraw to maxRedeem\n /// @dev Represents priceAssetPerShare, i.e. ASSET_UNIT/SHARE_UNIT\n uint256 redeemPrice;\n /// @dev Remaining deposit request in assets\n uint128 pendingDepositRequest;\n /// @dev Remaining redeem request in shares\n uint128 pendingRedeemRequest;\n /// @dev Assets that can be claimed using `claimCancelDepositRequest()`\n uint128 claimableCancelDepositRequest;\n /// @dev Shares that can be claimed using `claimCancelRedeemRequest()`\n uint128 claimableCancelRedeemRequest;\n /// @dev Indicates whether the depositRequest was requested to be cancelled\n bool pendingCancelDepositRequest;\n /// @dev Indicates whether the redeemRequest was requested to be cancelled\n bool pendingCancelRedeemRequest;\n}\n\ninterface IAsyncRequestManager is IAsyncDepositManager, IAsyncRedeemManager, IRequestManagerGatewayHandler {\n error ZeroAmountNotAllowed();\n error TransferNotAllowed();\n error CancellationIsPending();\n error NoPendingRequest();\n error ShareTokenAmountIsZero();\n error FailedRedeemRequest();\n error ExceedsDepositLimits();\n error ShareTokenTransferFailed();\n error ExceedsMaxRedeem();\n error ExceedsRedeemLimits();\n\n /// @notice Returns the investment state\n function investments(IBaseVault vaultAddr, address investor)\n external\n view\n returns (\n uint128 maxMint,\n uint128 maxWithdraw,\n uint256 depositPrice,\n uint256 redeemPrice,\n uint128 pendingDepositRequest,\n uint128 pendingRedeemRequest,\n uint128 claimableCancelDepositRequest,\n uint128 claimableCancelRedeemRequest,\n bool pendingCancelDepositRequest,\n bool pendingCancelRedeemRequest\n );\n}\n" + }, + "src/vaults/interfaces/investments/IBaseRequestManager.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\n\nimport {IPoolManager} from \"src/vaults/interfaces/IPoolManager.sol\";\nimport {IBaseVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\nimport {IPoolEscrow, IEscrow} from \"src/vaults/interfaces/IEscrow.sol\";\n\ninterface IBaseRequestManager {\n // --- Events ---\n event File(bytes32 indexed what, address data);\n\n error FileUnrecognizedParam();\n error SenderNotVault();\n error AssetNotAllowed();\n error ExceedsMaxDeposit();\n error AssetMismatch();\n error VaultAlreadyExists();\n error VaultDoesNotExist();\n\n /// @notice Updates contract parameters of type address.\n /// @param what The bytes32 representation of 'gateway' or 'poolManager'.\n /// @param data The new contract address.\n function file(bytes32 what, address data) external;\n\n /// @notice Converts the assets value to share decimals.\n function convertToShares(IBaseVault vault, uint256 _assets) external view returns (uint256 shares);\n\n /// @notice Converts the shares value to assets decimals.\n function convertToAssets(IBaseVault vault, uint256 _shares) external view returns (uint256 assets);\n\n /// @notice Returns the timestamp of the last share price update for a vaultAddr.\n function priceLastUpdated(IBaseVault vault) external view returns (uint64 lastUpdated);\n\n /// @notice Returns the PoolManager contract address.\n function poolManager() external view returns (IPoolManager poolManager);\n\n /// @notice The global escrow used for funds that are not yet free to be used for a specific pool\n function globalEscrow() external view returns (IEscrow escrow);\n\n /// @notice Escrow per pool. Funds are associated to a specific pool\n function poolEscrow(PoolId poolId) external view returns (IPoolEscrow);\n\n /// @notice Adds new vault for `poolId`, `scId` and `asset`.\n function addVault(PoolId poolId, ShareClassId scId, IBaseVault vault, address asset, AssetId assetId) external;\n\n /// @notice Removes `vault` from `who`'s authorized callers\n function removeVault(PoolId poolId, ShareClassId scId, IBaseVault vault, address asset, AssetId assetId) external;\n\n /// @notice Returns the address of the vault for a given pool, share class and asset\n function vaultByAssetId(PoolId poolId, ShareClassId scId, AssetId assetId)\n external\n view\n returns (IBaseVault vault);\n}\n" + }, + "src/vaults/interfaces/investments/IDepositManager.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IBaseRequestManager} from \"src/vaults/interfaces/investments/IBaseRequestManager.sol\";\nimport {IBaseVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\n\ninterface IDepositManager is IBaseRequestManager {\n /// @notice Processes owner's asset deposit after the epoch has been executed on the corresponding CP instance and\n /// the deposit order\n /// has been successfully processed (partial fulfillment possible).\n /// Shares are transferred from the escrow to the receiver. Amount of shares is computed based of the amount\n /// of assets and the owner's share price.\n /// @dev The assets required to fulfill the deposit are already locked in escrow upon calling requestDeposit.\n /// The shares required to fulfill the deposit have already been minted and transferred to the escrow on\n /// fulfillDepositRequest.\n /// Receiver has to pass all the share token restrictions in order to receive the shares.\n function deposit(IBaseVault vault, uint256 assets, address receiver, address owner)\n external\n returns (uint256 shares);\n\n /// @notice Processes owner's share mint after the epoch has been executed on the corresponding CP instance and the\n /// deposit order has\n /// been successfully processed (partial fulfillment possible).\n /// Shares are transferred from the escrow to the receiver. Amount of assets is computed based of the amount\n /// of shares and the owner's share price.\n /// @dev The assets required to fulfill the mint are already locked in escrow upon calling requestDeposit.\n /// The shares required to fulfill the mint have already been minted and transferred to the escrow on\n /// fulfillDepositRequest.\n /// Receiver has to pass all the share token restrictions in order to receive the shares.\n function mint(IBaseVault vault, uint256 shares, address receiver, address owner)\n external\n returns (uint256 assets);\n\n /// @notice Returns the max amount of assets based on the unclaimed amount of shares after at least one successful\n /// deposit order fulfillment on the corresponding CP instance.\n function maxDeposit(IBaseVault vault, address user) external view returns (uint256);\n\n /// @notice Returns the max amount of shares a user can claim after at least one successful deposit order\n /// fulfillment on the corresponding CP instance.\n function maxMint(IBaseVault vault, address user) external view returns (uint256 shares);\n}\n" + }, + "src/vaults/interfaces/investments/IRedeemManager.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IBaseRequestManager} from \"src/vaults/interfaces/investments/IBaseRequestManager.sol\";\nimport {IBaseVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\n\ninterface IRedeemManager is IBaseRequestManager {\n event TriggerRedeemRequest(\n uint64 indexed poolId,\n bytes16 indexed scId,\n address user,\n address indexed asset,\n uint256 tokenId,\n uint128 shares\n );\n\n /// @notice Processes owner's share redemption after the epoch has been executed on the corresponding CP instance\n /// and the redeem order\n /// has been successfully processed (partial fulfillment possible).\n /// Assets are transferred from the escrow to the receiver. Amount of assets is computed based of the amount\n /// of shares and the owner's share price.\n /// @dev The shares required to fulfill the redemption were already locked in escrow on requestRedeem and burned\n /// on fulfillRedeemRequest.\n /// The assets required to fulfill the redemption have already been reserved in escrow on\n /// fulfillRedeemtRequest.\n function redeem(IBaseVault vault, uint256 shares, address receiver, address owner)\n external\n returns (uint256 assets);\n\n /// @notice Processes owner's asset withdrawal after the epoch has been executed on the corresponding CP instance\n /// and the redeem order\n /// has been successfully processed (partial fulfillment possible).\n /// Assets are transferred from the escrow to the receiver. Amount of shares is computed based of the amount\n /// of shares and the owner's share price.\n /// @dev The shares required to fulfill the withdrawal were already locked in escrow on requestRedeem and burned\n /// on fulfillRedeemRequest.\n /// The assets required to fulfill the withdrawal have already been reserved in escrow on\n /// fulfillRedeemtRequest.\n function withdraw(IBaseVault vault, uint256 assets, address receiver, address owner)\n external\n returns (uint256 shares);\n\n /// @notice Returns the max amount of shares based on the unclaimed number of assets after at least one successful\n /// redeem order fulfillment on the corresponding CP instance.\n function maxRedeem(IBaseVault vault, address user) external view returns (uint256 shares);\n\n /// @notice Returns the max amount of assets a user can claim after at least one successful redeem order fulfillment\n /// on the corresponding CP instance.\n function maxWithdraw(IBaseVault vault, address user) external view returns (uint256 assets);\n}\n" + }, + "src/vaults/interfaces/investments/ISyncDepositManager.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IDepositManager} from \"src/vaults/interfaces/investments/IDepositManager.sol\";\nimport {IBaseVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\n\ninterface ISyncDepositManager is IDepositManager {\n function previewDeposit(IBaseVault vault, address sender, uint256 assets) external view returns (uint256);\n function previewMint(IBaseVault vault, address sender, uint256 shares) external view returns (uint256);\n}\n" + }, + "src/vaults/interfaces/investments/ISyncRequestManager.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {D18} from \"src/misc/types/D18.sol\";\n\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nimport {IUpdateContract} from \"src/vaults/interfaces/IUpdateContract.sol\";\nimport {ISyncDepositManager} from \"src/vaults/interfaces/investments/ISyncDepositManager.sol\";\n\n/// @dev Solely used locally as protection against stack-too-deep\nstruct Prices {\n /// @dev Price of 1 asset unit per share unit\n D18 assetPerShare;\n /// @dev Price of 1 pool unit per asset unit\n D18 poolPerAsset;\n /// @dev Price of 1 pool unit per share unit\n D18 poolPerShare;\n}\n\ninterface ISyncDepositValuation {\n /// @notice Returns the pool price per share for a given pool and share class, asset, and asset id.\n // The provided price is defined as POOL_UNIT/SHARE_UNIT.\n ///\n /// @param poolId The pool id\n /// @param scId The share class id\n /// @return price The pool price per share\n function pricePoolPerShare(PoolId poolId, ShareClassId scId) external view returns (D18 price);\n}\n\ninterface ISyncRequestManager is ISyncDepositManager, ISyncDepositValuation, IUpdateContract {\n event SetValuation(PoolId indexed poolId, ShareClassId indexed scId, address valuation);\n event SetMaxReserve(\n PoolId indexed poolId, ShareClassId indexed scId, address asset, uint256 tokenId, uint128 maxReserve\n );\n\n error ExceedsMaxMint();\n error ShareTokenDoesNotExist();\n error SecondaryManagerDoesNotExist();\n\n /// @notice Sets the valuation for a specific pool and share class.\n ///\n /// @param poolId The id of the pool\n /// @param scId The id of the share class\n /// @param valuation The address of the valuation contract\n function setValuation(PoolId poolId, ShareClassId scId, address valuation) external;\n\n /// @notice Sets the max reserve for a specific pool, share class and asset.\n ///\n /// @param poolId The id of the pool\n /// @param scId The id of the share class\n /// @param asset The address of the asset\n /// @param tokenId The asset token id, i.e. 0 for ERC20, or the token id for ERC6909\n /// @param maxReserve The amount of maximum reserve\n function setMaxReserve(PoolId poolId, ShareClassId scId, address asset, uint256 tokenId, uint128 maxReserve)\n external;\n\n /// @notice Returns the all three prices for a given pool, share class, asset, and asset id.\n ///\n /// @param poolId The pool id\n /// @param scId The share class id\n /// @param assetId The asset id corresponding to the asset and tokenId\n /// @return priceData The asset price per share, pool price per asset, and pool price per share\n function prices(PoolId poolId, ShareClassId scId, AssetId assetId)\n external\n view\n returns (Prices memory priceData);\n}\n" + }, + "src/vaults/interfaces/token/IShareToken.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IERC20Metadata} from \"src/misc/interfaces/IERC20.sol\";\nimport {IERC7575Share} from \"src/misc/interfaces/IERC7575.sol\";\n\ninterface IERC1404 {\n /// @notice Detects if a transfer will be reverted and if so returns an appropriate reference code\n /// @param from Sending address\n /// @param to Receiving address\n /// @param value Amount of tokens being transferred\n /// @return Code by which to reference message for rejection reasoning\n /// @dev Overwrite with your custom transfer restriction logic\n function detectTransferRestriction(address from, address to, uint256 value) external view returns (uint8);\n\n /// @notice Returns a human-readable message for a given restriction code\n /// @param restrictionCode Identifier for looking up a message\n /// @return Text showing the restriction's reasoning\n /// @dev Overwrite with your custom message and restrictionCode handling\n function messageForTransferRestriction(uint8 restrictionCode) external view returns (string memory);\n}\n\ninterface IShareToken is IERC20Metadata, IERC7575Share, IERC1404 {\n // --- Events ---\n event File(bytes32 indexed what, address data);\n event SetHookData(address indexed user, bytes16 data);\n\n // --- Errors ---\n error NotAuthorizedOrHook();\n error ExceedsMaxSupply();\n error RestrictionsFailed();\n\n struct Balance {\n /// @dev The user balance is limited to uint128. This is safe because the decimals are limited to 18,\n /// thus the max balance is 2^128-1 / 10**18 = 3.40 * 10**20. This is also enforced on mint.\n uint128 amount;\n /// @dev There are 16 bytes that are used to store hook data (e.g. restrictions for users).\n bytes16 hookData;\n }\n\n // --- Administration ---\n /// @notice returns the hook that transfers perform callbacks to\n /// @dev MUST comply to `IHook` interface\n function hook() external view returns (address);\n\n /// @notice Updates a contract parameter\n /// @param what Accepts a bytes32 representation of 'name', 'symbol'\n function file(bytes32 what, string memory data) external;\n\n /// @notice Updates a contract parameter\n /// @param what Accepts a bytes32 representation of 'hook'\n function file(bytes32 what, address data) external;\n\n /// @notice updates the vault for a given `asset`\n function updateVault(address asset, address vault_) external;\n\n // --- ERC20 overrides ---\n /// @notice returns the 16 byte hook data of the given `user`.\n /// @dev Stored in the 128 most significant bits of the user balance\n function hookDataOf(address user) external view returns (bytes16);\n\n /// @notice update the 16 byte hook data of the given `user`\n function setHookData(address user, bytes16 hookData) external;\n\n /// @notice Function to mint tokens\n function mint(address user, uint256 value) external;\n\n /// @notice Function to burn tokens\n function burn(address user, uint256 value) external;\n\n /// @notice Checks if the tokens can be transferred given the input values\n function checkTransferRestriction(address from, address to, uint256 value) external view returns (bool);\n\n /// @notice Performs an authorized transfer, with `sender` as the given sender.\n /// @dev Requires allowance if `sender` != `from`\n function authTransferFrom(address sender, address from, address to, uint256 amount) external returns (bool);\n}\n" + }, + "src/vaults/legacy/LegacyVaultAdapter.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nimport {ILegacyVault} from \"src/vaults/legacy/interfaces/ILegacyVault.sol\";\nimport {IInvestmentManager} from \"src/vaults/legacy/interfaces/IInvestmentManager.sol\";\nimport {ILegacyVaultAdapter} from \"src/vaults/legacy/interfaces/ILegacyVaultAdapter.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\nimport {AsyncVault} from \"src/vaults/AsyncVault.sol\";\nimport {IAsyncRequestManager} from \"src/vaults/interfaces/investments/IAsyncRequestManager.sol\";\nimport {BaseAsyncRedeemVault, IAsyncRedeemVault} from \"src/vaults/BaseVaults.sol\";\n\n/// @title LegacyVaultAdapter\n/// @notice An adapter connecting legacy ERC-7540 vaults from Centrifuge V2 to Centrifuge V3.\n///\n/// @dev This adapter acts as an `IInvestmentManager` for a single legacy `ILegacyVault` vault from Centrifuge V2.\n/// At the same time it acts like a new `IAsyncVault` for the `IAsyncRequestManager` manager of Centrifuge V3.\n/// The adapter needs to be deployed per legacy vault and allows a seamless interaction between Centrifuge V2\n/// vaults and Centrifuge V3 infrastructure. Thereby, allowing to migrate existing vaults to the new system.\ncontract LegacyVaultAdapter is AsyncVault, ILegacyVaultAdapter, IInvestmentManager {\n uint64 public immutable legacyPoolId;\n bytes16 public immutable legacyTrancheId;\n ILegacyVault public immutable legacyVault;\n\n constructor(\n ILegacyVault legacyVault_,\n PoolId poolId,\n uint64 legacyPoolId_,\n ShareClassId scId,\n bytes16 legacyTrancheId_,\n address asset,\n IShareToken token,\n address root,\n IAsyncRequestManager manager\n ) AsyncVault(poolId, scId, asset, token, root, manager) {\n require(legacyVault_.poolId() == legacyPoolId_, NotLegacyPoolId(legacyPoolId_, legacyVault_.poolId()));\n require(\n legacyVault_.trancheId() == legacyTrancheId_, NotLegacyTrancheId(legacyTrancheId_, legacyVault_.trancheId())\n );\n require(legacyVault_.asset() == asset, NotLegacyAsset(asset, legacyVault_.asset()));\n require(legacyVault_.share() == address(token), NotLegacyShare(address(token), legacyVault_.share()));\n\n legacyPoolId = legacyPoolId_;\n legacyTrancheId = legacyTrancheId_;\n legacyVault = legacyVault_;\n }\n\n /// @dev Check if the msg.sender is the legacy vault\n modifier legacy() {\n require(msg.sender == address(legacyVault), NotLegacyVault(msg.sender, address(legacyVault)));\n _;\n }\n\n //----------------------------------------------------------------------------------------------\n // IInvestmentManager handlers\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IInvestmentManager\n function requestDeposit(address, /* vault */ uint256 assets, address receiver, address owner, address source)\n public\n legacy\n returns (bool)\n {\n return asyncManager().requestDeposit(this, assets, receiver, owner, source);\n }\n\n /// @inheritdoc IInvestmentManager\n function requestRedeem(address, /* vault */ uint256 shares, address receiver, address owner, address source)\n public\n legacy\n returns (bool)\n {\n return asyncManager().requestRedeem(this, shares, receiver, owner, source);\n }\n\n /// @inheritdoc IInvestmentManager\n function cancelDepositRequest(address, /* vault */ address owner, address source) public legacy {\n return asyncManager().cancelDepositRequest(this, owner, source);\n }\n\n /// @inheritdoc IInvestmentManager\n function cancelRedeemRequest(address, /* vault */ address owner, address source) public legacy {\n return asyncManager().cancelRedeemRequest(this, owner, source);\n }\n\n //----------------------------------------------------------------------------------------------\n // IInvestmentManager view methods\n //----------------------------------------------------------------------------------------------\n\n function escrow() public view returns (address) {\n return address(manager.globalEscrow());\n }\n\n /// @inheritdoc IInvestmentManager\n function convertToShares(address, /* vault */ uint256 _assets) public view returns (uint256 shares) {\n shares = asyncManager().convertToShares(this, _assets);\n }\n\n /// @inheritdoc IInvestmentManager\n function convertToAssets(address, /* vault */ uint256 _shares) public view returns (uint256 assets) {\n assets = asyncManager().convertToAssets(this, _shares);\n }\n\n /// @inheritdoc IInvestmentManager\n function maxDeposit(address, /* vault */ address user) public view returns (uint256 assets) {\n assets = asyncManager().maxDeposit(this, user);\n }\n\n /// @inheritdoc IInvestmentManager\n function maxMint(address, /* vault */ address user) public view returns (uint256 shares) {\n shares = asyncManager().maxMint(this, user);\n }\n\n /// @inheritdoc IInvestmentManager\n function maxWithdraw(address, /* vault */ address user) public view returns (uint256 assets) {\n assets = asyncManager().maxWithdraw(this, user);\n }\n\n /// @inheritdoc IInvestmentManager\n function maxRedeem(address, /* vault */ address user) public view returns (uint256 shares) {\n shares = asyncManager().maxRedeem(this, user);\n }\n\n /// @inheritdoc IInvestmentManager\n function pendingDepositRequest(address, /* vault */ address user) public view returns (uint256 assets) {\n assets = asyncManager().pendingDepositRequest(this, user);\n }\n\n /// @inheritdoc IInvestmentManager\n function pendingRedeemRequest(address, /* vault */ address user) public view returns (uint256 shares) {\n shares = asyncManager().pendingRedeemRequest(this, user);\n }\n\n /// @inheritdoc IInvestmentManager\n function pendingCancelDepositRequest(address, /* vault */ address user) public view returns (bool isPending) {\n isPending = asyncManager().pendingCancelDepositRequest(this, user);\n }\n\n /// @inheritdoc IInvestmentManager\n function pendingCancelRedeemRequest(address, /* vault */ address user) public view returns (bool isPending) {\n isPending = asyncManager().pendingCancelRedeemRequest(this, user);\n }\n\n /// @inheritdoc IInvestmentManager\n function claimableCancelDepositRequest(address, /* vault */ address user) public view returns (uint256 assets) {\n assets = asyncManager().claimableCancelDepositRequest(this, user);\n }\n\n /// @inheritdoc IInvestmentManager\n function claimableCancelRedeemRequest(address, /* vault */ address user) public view returns (uint256 shares) {\n shares = asyncManager().claimableCancelRedeemRequest(this, user);\n }\n\n /// @inheritdoc IInvestmentManager\n function priceLastUpdated(address /* vault */ ) public view returns (uint64 lastUpdated) {\n lastUpdated = manager.priceLastUpdated(this);\n }\n\n //----------------------------------------------------------------------------------------------\n // IInvestmentManager vault claim methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IInvestmentManager\n function deposit(address, /* vault */ uint256 assets, address receiver, address owner)\n public\n legacy\n returns (uint256 shares)\n {\n shares = asyncManager().deposit(this, assets, receiver, owner);\n }\n\n /// @inheritdoc IInvestmentManager\n function mint(address, /* vault */ uint256 shares, address receiver, address owner)\n public\n legacy\n returns (uint256 assets)\n {\n assets = asyncManager().mint(this, shares, receiver, owner);\n }\n\n /// @inheritdoc IInvestmentManager\n function redeem(address, /* vault */ uint256 shares, address receiver, address owner)\n public\n legacy\n returns (uint256 assets)\n {\n assets = asyncManager().redeem(this, shares, receiver, owner);\n }\n\n /// @inheritdoc IInvestmentManager\n function withdraw(address, /* vault */ uint256 assets, address receiver, address owner)\n public\n legacy\n returns (uint256 shares)\n {\n shares = asyncManager().withdraw(this, assets, receiver, owner);\n }\n\n /// @inheritdoc IInvestmentManager\n function claimCancelDepositRequest(address, /* vault */ address receiver, address owner)\n public\n legacy\n returns (uint256 assets)\n {\n assets = asyncManager().claimCancelDepositRequest(this, receiver, owner);\n }\n\n /// @inheritdoc IInvestmentManager\n function claimCancelRedeemRequest(address, /* vault */ address receiver, address owner)\n public\n legacy\n returns (uint256 shares)\n {\n shares = asyncManager().claimCancelRedeemRequest(this, receiver, owner);\n }\n\n //----------------------------------------------------------------------------------------------\n // Event emitters\n //----------------------------------------------------------------------------------------------\n\n function onDepositClaimable(address controller, uint256 assets, uint256 shares) public override auth {\n legacyVault.onDepositClaimable(controller, assets, shares);\n }\n\n function onCancelDepositClaimable(address controller, uint256 assets) public override auth {\n legacyVault.onCancelDepositClaimable(controller, assets);\n }\n\n function onRedeemRequest(address controller, address owner, uint256 shares)\n public\n override(BaseAsyncRedeemVault, IAsyncRedeemVault)\n auth\n {\n legacyVault.onRedeemRequest(controller, owner, shares);\n }\n\n function onRedeemClaimable(address controller, uint256 assets, uint256 shares)\n public\n override(BaseAsyncRedeemVault, IAsyncRedeemVault)\n auth\n {\n legacyVault.onRedeemClaimable(controller, assets, shares);\n }\n\n function onCancelRedeemClaimable(address controller, uint256 shares)\n public\n override(BaseAsyncRedeemVault, IAsyncRedeemVault)\n auth\n {\n legacyVault.onCancelRedeemClaimable(controller, shares);\n }\n}\n" + }, + "src/vaults/legacy/interfaces/IInvestmentManager.sol": { + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.5.0;\n\n/// @notice A stripped down version of the Centrifuge V2 investment manager.\n///\n/// @dev This interface is needed to ensure adapters for legacy vaults are provided with the expected interface.\ninterface IInvestmentManager {\n /// @notice Documentation see Centrifuge V2 repository.\n function escrow() external view returns (address);\n\n // --- Outgoing message handling ---\n /// @notice Documentation see Centrifuge V2 repository.\n function requestDeposit(address vault, uint256 assets, address receiver, address owner, address source)\n external\n returns (bool);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function requestRedeem(address vault, uint256 shares, address receiver, address, /* owner */ address source)\n external\n returns (bool);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function cancelDepositRequest(address vault, address owner, address source) external;\n\n /// @notice Documentation see Centrifuge V2 repository.\n function cancelRedeemRequest(address vault, address owner, address source) external;\n\n // --- View functions ---\n /// @notice Documentation see Centrifuge V2 repository.\n function convertToShares(address vault, uint256 _assets) external view returns (uint256 shares);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function convertToAssets(address vault, uint256 _shares) external view returns (uint256 assets);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function maxDeposit(address vault, address user) external view returns (uint256);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function maxMint(address vault, address user) external view returns (uint256 shares);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function maxWithdraw(address vault, address user) external view returns (uint256 assets);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function maxRedeem(address vault, address user) external view returns (uint256 shares);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function pendingDepositRequest(address vault, address user) external view returns (uint256 assets);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function pendingRedeemRequest(address vault, address user) external view returns (uint256 shares);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function pendingCancelDepositRequest(address vault, address user) external view returns (bool isPending);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function pendingCancelRedeemRequest(address vault, address user) external view returns (bool isPending);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function claimableCancelDepositRequest(address vault, address user) external view returns (uint256 assets);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function claimableCancelRedeemRequest(address vault, address user) external view returns (uint256 shares);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function priceLastUpdated(address vault) external view returns (uint64 lastUpdated);\n\n // --- Vault claim functions ---\n /// @notice Documentation see Centrifuge V2 repository.\n function deposit(address vault, uint256 assets, address receiver, address owner)\n external\n returns (uint256 shares);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function mint(address vault, uint256 shares, address receiver, address owner) external returns (uint256 assets);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function redeem(address vault, uint256 shares, address receiver, address owner) external returns (uint256 assets);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function withdraw(address vault, uint256 assets, address receiver, address owner)\n external\n returns (uint256 shares);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function claimCancelDepositRequest(address vault, address receiver, address owner)\n external\n returns (uint256 assets);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function claimCancelRedeemRequest(address vault, address receiver, address owner)\n external\n returns (uint256 shares);\n}\n" + }, + "src/vaults/legacy/interfaces/ILegacyVault.sol": { + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.5.0;\n\n/// @notice A stripped down version of the Centrifuge V2 ERC-7540 vault.\n///\n/// @dev This interface is needed to ensure adapters for legacy vaults are provided with the expected interface.\ninterface ILegacyVault {\n /// @notice Documentation see Centrifuge V2 repository.\n function poolId() external view returns (uint64);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function trancheId() external view returns (bytes16);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function asset() external view returns (address);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function share() external view returns (address);\n\n /// @notice Callback when a redeem Request is triggered externally;\n function onRedeemRequest(address controller, address owner, uint256 shares) external;\n\n /// @notice Callback when a deposit Request becomes claimable\n function onDepositClaimable(address owner, uint256 assets, uint256 shares) external;\n\n /// @notice Callback when a redeem Request becomes claimable\n function onRedeemClaimable(address owner, uint256 assets, uint256 shares) external;\n\n /// @notice Callback when a claim deposit Request becomes claimable\n function onCancelDepositClaimable(address owner, uint256 assets) external;\n\n /// @notice Callback when a claim redeem Request becomes claimable\n function onCancelRedeemClaimable(address owner, uint256 shares) external;\n}\n" + }, + "src/vaults/legacy/interfaces/ILegacyVaultAdapter.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\ninterface ILegacyVaultAdapter {\n error NotLegacyVault(address sender, address legacyVault);\n error NotLegacyPoolId(uint64 providedPoolId, uint64 legacyPoolId);\n error NotLegacyTrancheId(bytes16 providedTrancheId, bytes16 legacyTrancheId);\n error NotLegacyAsset(address providedAsset, address legacyAsset);\n error NotLegacyShare(address providedShare, address legacyShare);\n}\n" + }, + "src/vaults/token/ShareToken.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {ERC20} from \"src/misc/ERC20.sol\";\nimport {IERC20, IERC20Metadata} from \"src/misc/interfaces/IERC20.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {IERC7575Share, IERC165} from \"src/misc/interfaces/IERC7575.sol\";\n\nimport {\n IHook,\n HookData,\n SUCCESS_CODE_ID,\n SUCCESS_MESSAGE,\n ERROR_CODE_ID,\n ERROR_MESSAGE\n} from \"src/common/interfaces/IHook.sol\";\nimport {IShareToken, IERC1404} from \"src/vaults/interfaces/token/IShareToken.sol\";\n\n/// @title Share Token\n/// @notice Extension of ERC20 + ERC1404,\n/// integrating an external hook optionally for ERC20 callbacks and ERC1404 checks.\ncontract ShareToken is ERC20, IShareToken {\n using MathLib for uint256;\n\n mapping(address => Balance) private balances;\n\n /// @inheritdoc IShareToken\n address public hook;\n\n /// @inheritdoc IERC7575Share\n mapping(address asset => address) public vault;\n\n constructor(uint8 decimals_) ERC20(decimals_) {}\n\n modifier authOrHook() {\n require(wards[msg.sender] == 1 || msg.sender == hook, NotAuthorizedOrHook());\n _;\n }\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IShareToken\n function file(bytes32 what, address data) external authOrHook {\n if (what == \"hook\") hook = data;\n else revert FileUnrecognizedParam();\n emit File(what, data);\n }\n\n /// @inheritdoc IShareToken\n function file(bytes32 what, string memory data) public override(ERC20, IShareToken) auth {\n super.file(what, data);\n }\n\n /// @inheritdoc IShareToken\n function updateVault(address asset, address vault_) external auth {\n vault[asset] = vault_;\n emit VaultUpdate(asset, vault_);\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-20 overrides\n //----------------------------------------------------------------------------------------------\n\n function _balanceOf(address user) internal view override returns (uint256) {\n return balances[user].amount;\n }\n\n function _setBalance(address user, uint256 value) internal override {\n balances[user].amount = value.toUint128();\n }\n\n /// @inheritdoc IShareToken\n function hookDataOf(address user) public view returns (bytes16) {\n return balances[user].hookData;\n }\n\n /// @inheritdoc IShareToken\n function setHookData(address user, bytes16 hookData) public authOrHook {\n balances[user].hookData = hookData;\n emit SetHookData(user, hookData);\n }\n\n /// @inheritdoc IERC20\n function transfer(address to, uint256 value) public override(ERC20, IERC20) returns (bool success) {\n success = super.transfer(to, value);\n _onTransfer(msg.sender, to, value);\n }\n\n /// @inheritdoc IERC20\n function transferFrom(address from, address to, uint256 value)\n public\n override(ERC20, IERC20)\n returns (bool success)\n {\n success = super.transferFrom(from, to, value);\n _onTransfer(from, to, value);\n }\n\n /// @inheritdoc IShareToken\n function mint(address to, uint256 value) public override(ERC20, IShareToken) {\n super.mint(to, value);\n require(totalSupply <= type(uint128).max, ExceedsMaxSupply());\n _onTransfer(address(0), to, value);\n }\n\n /// @inheritdoc IShareToken\n function burn(address from, uint256 value) public override(ERC20, IShareToken) {\n super.burn(from, value);\n _onTransfer(from, address(0), value);\n }\n\n function _onTransfer(address from, address to, uint256 value) internal {\n address hook_ = hook;\n require(\n hook_ == address(0)\n || IHook(hook_).onERC20Transfer(from, to, value, HookData(hookDataOf(from), hookDataOf(to)))\n == IHook.onERC20Transfer.selector,\n RestrictionsFailed()\n );\n }\n\n /// @inheritdoc IShareToken\n function authTransferFrom(address sender, address from, address to, uint256 value)\n public\n auth\n returns (bool success)\n {\n success = _transferFrom(sender, from, to, value);\n address hook_ = hook;\n if (hook_ != address(0)) {\n IHook(hook_).onERC20AuthTransfer(sender, from, to, value, HookData(hookDataOf(from), hookDataOf(to)));\n }\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-1404\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IShareToken\n function checkTransferRestriction(address from, address to, uint256 value) public view returns (bool) {\n return detectTransferRestriction(from, to, value) == SUCCESS_CODE_ID;\n }\n\n /// @inheritdoc IERC1404\n function detectTransferRestriction(address from, address to, uint256 value) public view returns (uint8) {\n address hook_ = hook;\n if (hook_ == address(0)) return SUCCESS_CODE_ID;\n return IHook(hook_).checkERC20Transfer(from, to, value, HookData(hookDataOf(from), hookDataOf(to)))\n ? SUCCESS_CODE_ID\n : ERROR_CODE_ID;\n }\n\n /// @inheritdoc IERC1404\n function messageForTransferRestriction(uint8 restrictionCode) external pure returns (string memory) {\n return restrictionCode == SUCCESS_CODE_ID ? SUCCESS_MESSAGE : ERROR_MESSAGE;\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-165\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC165\n function supportsInterface(bytes4 interfaceId) external pure override returns (bool) {\n return interfaceId == type(IERC7575Share).interfaceId || interfaceId == type(IERC165).interfaceId;\n }\n}\n" + } + }, + "settings": { + "remappings": [ + "forge-std/=lib/forge-std/src/", + "@chimera/=lib/chimera/src/", + "chimera/=lib/chimera/src/", + "ds-test/=lib/chimera/lib/forge-std/lib/ds-test/src/" + ], + "optimizer": { "enabled": true, "runs": 1 }, + "metadata": { + "useLiteralContent": false, + "bytecodeHash": "none", + "appendCBOR": true + }, + "outputSelection": { + "lib/forge-std/src/interfaces/IERC165.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/GasService.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/Gateway.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/Guardian.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/MessageDispatcher.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/MessageProcessor.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/Root.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/TokenRecoverer.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/adapters/AxelarAdapter.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/adapters/WormholeAdapter.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/interfaces/IAdapter.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/interfaces/IAxelarAdapter.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/interfaces/IGasService.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/interfaces/IGateway.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/interfaces/IGatewayHandlers.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/interfaces/IGatewaySenders.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/interfaces/IGuardian.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/interfaces/IGuardianActions.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/interfaces/IHook.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/interfaces/IMessageDispatcher.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/interfaces/IMessageHandler.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/interfaces/IMessageProcessor.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/interfaces/IMessageProperties.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/interfaces/IMessageSender.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/interfaces/IRoot.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/interfaces/ITokenRecoverer.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/interfaces/IWormholeAdapter.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/libraries/MessageLib.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/libraries/MessageProofLib.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/libraries/PricingLib.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/types/AccountId.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/types/AssetId.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/types/PoolId.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/types/ShareClassId.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/hooks/FreezeOnly.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/hooks/FullRestrictions.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/hooks/RedemptionRestrictions.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/hooks/interfaces/IFreezable.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/hooks/interfaces/IMemberlist.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/hub/Accounting.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/hub/Holdings.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/hub/Hub.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/hub/HubRegistry.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/hub/ShareClassManager.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/hub/interfaces/IAccounting.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/hub/interfaces/IHoldings.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/hub/interfaces/IHub.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/hub/interfaces/IHubRegistry.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/hub/interfaces/IShareClassManager.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/misc/Auth.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/misc/BaseValuation.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/misc/ERC20.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/misc/IdentityValuation.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/misc/Multicall.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/misc/Recoverable.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/misc/ReentrancyProtection.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/misc/interfaces/IAuth.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/misc/interfaces/IBaseValuation.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/misc/interfaces/IERC20.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/misc/interfaces/IERC6909.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/misc/interfaces/IERC7540.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/misc/interfaces/IERC7575.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/misc/interfaces/IERC7726.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/misc/interfaces/IIdentityValuation.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/misc/interfaces/IMulticall.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/misc/interfaces/IRecoverable.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/misc/libraries/ArrayLib.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/misc/libraries/BitmapLib.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/misc/libraries/BytesLib.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/misc/libraries/CastLib.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/misc/libraries/EIP712Lib.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/misc/libraries/MathLib.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/misc/libraries/SafeTransferLib.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/misc/libraries/SignatureLib.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/misc/libraries/StringLib.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/misc/libraries/TransientArrayLib.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/misc/libraries/TransientBytesLib.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/misc/libraries/TransientStorageLib.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/misc/types/D18.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/AsyncRequestManager.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/AsyncVault.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/BalanceSheet.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/BaseRequestManager.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/BaseVaults.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/Escrow.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/PoolManager.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/SyncDepositVault.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/SyncRequestManager.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/VaultRouter.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/factories/AsyncVaultFactory.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/factories/PoolEscrowFactory.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/factories/SyncDepositVaultFactory.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/factories/TokenFactory.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/interfaces/IBalanceSheet.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/interfaces/IBaseVaults.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/interfaces/IEscrow.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/interfaces/IPoolManager.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/interfaces/IUpdateContract.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/interfaces/IVaultRouter.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/interfaces/factories/IPoolEscrowFactory.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/interfaces/factories/ITokenFactory.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/interfaces/factories/IVaultFactory.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/interfaces/investments/IAsyncDepositManager.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/interfaces/investments/IAsyncRedeemManager.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/interfaces/investments/IAsyncRequestManager.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/interfaces/investments/IBaseRequestManager.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/interfaces/investments/IDepositManager.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/interfaces/investments/IRedeemManager.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/interfaces/investments/ISyncDepositManager.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/interfaces/investments/ISyncRequestManager.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/interfaces/token/IShareToken.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/legacy/LegacyVaultAdapter.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/legacy/interfaces/IInvestmentManager.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/legacy/interfaces/ILegacyVault.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/legacy/interfaces/ILegacyVaultAdapter.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/token/ShareToken.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + } + }, + "evmVersion": "cancun", + "viaIR": true, + "libraries": {} + } +} diff --git a/crates/resolc/src/tests/data/standard_json/pvm_codegen_all_wildcard.json b/crates/resolc/src/tests/data/standard_json/pvm_codegen_all_wildcard.json new file mode 100644 index 0000000..ffdaeb2 --- /dev/null +++ b/crates/resolc/src/tests/data/standard_json/pvm_codegen_all_wildcard.json @@ -0,0 +1,375 @@ +{ + "language": "Solidity", + "sources": { + "lib/forge-std/src/interfaces/IERC165.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.6.2;\n\ninterface IERC165 {\n /// @notice Query if a contract implements an interface\n /// @param interfaceID The interface identifier, as specified in ERC-165\n /// @dev Interface identification is specified in ERC-165. This function\n /// uses less than 30,000 gas.\n /// @return `true` if the contract implements `interfaceID` and\n /// `interfaceID` is not 0xffffffff, `false` otherwise\n function supportsInterface(bytes4 interfaceID) external view returns (bool);\n}\n" + }, + "src/common/GasService.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IGasService} from \"src/common/interfaces/IGasService.sol\";\n\n/// @title GasService\n/// @notice This is a utility contract used to determine the execution gas limit\n/// for a payload being sent across all supported adapters.\ncontract GasService is IGasService {\n uint128 internal immutable _maxBatchSize;\n uint128 internal immutable _messageGasLimit;\n\n constructor(uint128 maxBatchSize_, uint128 messageGasLimit) {\n _maxBatchSize = maxBatchSize_;\n _messageGasLimit = messageGasLimit;\n }\n\n /// @inheritdoc IGasService\n function maxBatchSize(uint16) public view returns (uint128) {\n return _maxBatchSize;\n }\n\n /// @inheritdoc IGasService\n function gasLimit(uint16, bytes calldata) public view returns (uint128) {\n return _messageGasLimit;\n }\n}\n" + }, + "src/common/Gateway.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {ArrayLib} from \"src/misc/libraries/ArrayLib.sol\";\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {Recoverable, IRecoverable, ETH_ADDRESS} from \"src/misc/Recoverable.sol\";\nimport {TransientArrayLib} from \"src/misc/libraries/TransientArrayLib.sol\";\nimport {TransientBytesLib} from \"src/misc/libraries/TransientBytesLib.sol\";\nimport {TransientStorageLib} from \"src/misc/libraries/TransientStorageLib.sol\";\n\nimport {IRoot} from \"src/common/interfaces/IRoot.sol\";\nimport {IGasService} from \"src/common/interfaces/IGasService.sol\";\nimport {IAdapter} from \"src/common/interfaces/IAdapter.sol\";\nimport {IMessageProcessor} from \"src/common/interfaces/IMessageProcessor.sol\";\nimport {IMessageSender} from \"src/common/interfaces/IMessageSender.sol\";\nimport {IGateway} from \"src/common/interfaces/IGateway.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {IGatewayHandler} from \"src/common/interfaces/IGatewayHandlers.sol\";\nimport {MessageProofLib} from \"src/common/libraries/MessageProofLib.sol\";\n\n/// @title Gateway\n/// @notice Routing contract that forwards outgoing messages to multiple adapters (1 full message, n-1 proofs)\n/// and validates that multiple adapters have confirmed a message.\n///\n/// Supports batching multiple messages, as well as paying for methods manually or through pool-level subsidies.\n///\n/// Supports processing multiple duplicate messages in parallel by storing counts of messages\n/// and proofs that have been received. Also implements a retry method for failed messages.\ncontract Gateway is Auth, Recoverable, IGateway {\n using BytesLib for bytes;\n using MathLib for uint256;\n using MessageProofLib for *;\n using ArrayLib for uint16[8];\n using TransientStorageLib for bytes32;\n\n uint8 public constant MAX_ADAPTER_COUNT = 8;\n uint8 public constant PRIMARY_ADAPTER_ID = 1;\n PoolId public constant GLOBAL_POT = PoolId.wrap(0);\n uint256 public constant RECOVERY_CHALLENGE_PERIOD = 7 days;\n bytes32 public constant BATCH_LOCATORS_SLOT = bytes32(uint256(keccak256(\"Centrifuge/batch-locators\")) - 1);\n\n uint16 public immutable localCentrifugeId;\n\n // Dependencies\n IRoot public immutable root;\n IGasService public gasService;\n IMessageProcessor public processor;\n\n // Outbound & payments\n bool public transient isBatching;\n uint256 public transient fuel;\n address public transient transactionRefund;\n mapping(PoolId => Funds) public subsidy;\n mapping(uint16 centrifugeId => mapping(bytes32 batchHash => Underpaid)) public underpaid;\n\n // Adapters\n mapping(uint16 centrifugeId => IAdapter[]) public adapters;\n mapping(uint16 centrifugeId => mapping(IAdapter adapter => Adapter)) internal _activeAdapters;\n\n // Inbound & recoveries\n mapping(uint16 centrifugeId => mapping(bytes32 messageHash => uint256)) public failedMessages;\n mapping(uint16 centrifugeId => mapping(bytes32 batchHash => InboundBatch)) public inboundBatch;\n mapping(uint16 centrifugeId => mapping(IAdapter adapter => mapping(bytes32 payloadHash => uint256 timestamp)))\n public recoveries;\n\n constructor(uint16 localCentrifugeId_, IRoot root_, IGasService gasService_, address deployer) Auth(deployer) {\n localCentrifugeId = localCentrifugeId_;\n root = root_;\n gasService = gasService_;\n\n setRefundAddress(GLOBAL_POT, IRecoverable(address(this)));\n }\n\n modifier pauseable() {\n require(!root.paused(), Paused());\n _;\n }\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IGateway\n function file(bytes32 what, uint16 centrifugeId, IAdapter[] calldata addresses) external auth {\n if (what == \"adapters\") {\n uint8 quorum_ = addresses.length.toUint8();\n require(quorum_ != 0, EmptyAdapterSet());\n require(quorum_ <= MAX_ADAPTER_COUNT, ExceedsMax());\n\n // Increment session id to reset pending votes\n uint256 numAdapters = adapters[centrifugeId].length;\n uint64 sessionId =\n numAdapters > 0 ? _activeAdapters[centrifugeId][adapters[centrifugeId][0]].activeSessionId + 1 : 0;\n\n // Disable old adapters\n for (uint8 i; i < numAdapters; i++) {\n delete _activeAdapters[centrifugeId][adapters[centrifugeId][i]];\n }\n\n // Enable new adapters, setting quorum to number of adapters\n for (uint8 j; j < quorum_; j++) {\n require(_activeAdapters[centrifugeId][addresses[j]].id == 0, NoDuplicatesAllowed());\n\n // Ids are assigned sequentially starting at 1\n _activeAdapters[centrifugeId][addresses[j]] = Adapter(j + 1, quorum_, sessionId);\n }\n\n adapters[centrifugeId] = addresses;\n } else {\n revert FileUnrecognizedParam();\n }\n\n emit File(what, centrifugeId, addresses);\n }\n\n /// @inheritdoc IGateway\n function file(bytes32 what, address instance) external auth {\n if (what == \"gasService\") gasService = IGasService(instance);\n else if (what == \"processor\") processor = IMessageProcessor(instance);\n else revert FileUnrecognizedParam();\n\n emit File(what, instance);\n }\n\n receive() external payable {\n _subsidizePool(GLOBAL_POT, msg.sender, msg.value);\n }\n\n //----------------------------------------------------------------------------------------------\n // Incoming\n //----------------------------------------------------------------------------------------------\n\n /// @dev Handle an inbound payload\n function handle(uint16 centrifugeId, bytes calldata payload) external pauseable {\n _handle(centrifugeId, payload, IAdapter(msg.sender), false);\n }\n\n function _handle(uint16 centrifugeId, bytes calldata payload, IAdapter adapter_, bool isRecovery) internal {\n Adapter memory adapter = _activeAdapters[centrifugeId][adapter_];\n require(adapter.id != 0, InvalidAdapter());\n\n IMessageProcessor processor_ = processor;\n if (processor_.isMessageRecovery(payload)) {\n require(!isRecovery, RecoveryPayloadRecovered());\n return processor_.handle(centrifugeId, payload);\n }\n\n bool isMessageProof = payload.toUint8(0) == MessageProofLib.MESSAGE_PROOF_ID;\n\n // Verify adapter and parse message hash\n bytes32 batchHash;\n if (isMessageProof) {\n require(adapter.id != PRIMARY_ADAPTER_ID, NonProofAdapter());\n\n batchHash = payload.deserializeMessageProof();\n bytes32 payloadId = keccak256(abi.encodePacked(centrifugeId, localCentrifugeId, batchHash));\n emit HandleProof(centrifugeId, payloadId, batchHash, adapter_);\n } else {\n require(adapter.id == PRIMARY_ADAPTER_ID, NonBatchAdapter());\n\n batchHash = keccak256(payload);\n bytes32 payloadId = keccak256(abi.encodePacked(centrifugeId, localCentrifugeId, batchHash));\n emit HandleBatch(centrifugeId, payloadId, payload, adapter_);\n }\n\n // Special case for gas efficiency\n if (adapter.quorum == 1 && !isMessageProof) {\n _handleBatch(centrifugeId, payload);\n return;\n }\n\n InboundBatch storage state = inboundBatch[centrifugeId][batchHash];\n\n if (adapter.activeSessionId != state.sessionId) {\n // Clear votes from previous session\n delete state.votes;\n state.sessionId = adapter.activeSessionId;\n }\n\n // Increase vote\n state.votes[adapter.id - 1]++;\n\n if (state.votes.countNonZeroValues() >= adapter.quorum) {\n // Reduce votes by quorum\n state.votes.decreaseFirstNValues(adapter.quorum);\n\n if (isMessageProof) {\n _handleBatch(centrifugeId, state.pendingBatch);\n } else {\n _handleBatch(centrifugeId, payload);\n }\n\n // Only if there are no more pending messages, remove the pending message\n if (state.votes.isEmpty()) {\n delete state.pendingBatch;\n }\n } else if (!isMessageProof) {\n state.pendingBatch = payload;\n }\n }\n\n function _handleBatch(uint16 centrifugeId, bytes memory batch_) internal {\n IMessageProcessor processor_ = processor;\n bytes memory remaining = batch_;\n\n while (remaining.length > 0) {\n uint256 length = processor_.messageLength(remaining);\n bytes memory message = remaining.slice(0, length);\n remaining = remaining.slice(length, remaining.length - length);\n\n try processor_.handle(centrifugeId, message) {\n emit ExecuteMessage(centrifugeId, message);\n } catch (bytes memory err) {\n bytes32 messageHash = keccak256(message);\n failedMessages[centrifugeId][messageHash]++;\n emit FailMessage(centrifugeId, message, err);\n }\n }\n }\n\n /// @inheritdoc IGateway\n function retry(uint16 centrifugeId, bytes memory message) external pauseable {\n bytes32 messageHash = keccak256(message);\n require(failedMessages[centrifugeId][messageHash] > 0, NotFailedMessage());\n\n processor.handle(centrifugeId, message);\n failedMessages[centrifugeId][messageHash]--;\n\n emit ExecuteMessage(centrifugeId, message);\n }\n\n /// @inheritdoc IGatewayHandler\n function initiateRecovery(uint16 centrifugeId, IAdapter adapter, bytes32 payloadHash) external auth {\n require(_activeAdapters[centrifugeId][adapter].id != 0, InvalidAdapter());\n recoveries[centrifugeId][adapter][payloadHash] = block.timestamp + RECOVERY_CHALLENGE_PERIOD;\n emit InitiateRecovery(centrifugeId, payloadHash, adapter);\n }\n\n /// @inheritdoc IGatewayHandler\n function disputeRecovery(uint16 centrifugeId, IAdapter adapter, bytes32 payloadHash) external auth {\n delete recoveries[centrifugeId][adapter][payloadHash];\n emit DisputeRecovery(centrifugeId, payloadHash, adapter);\n }\n\n /// @inheritdoc IGateway\n function executeRecovery(uint16 centrifugeId, IAdapter adapter, bytes calldata payload) external {\n bytes32 payloadHash = keccak256(payload);\n uint256 recovery = recoveries[centrifugeId][adapter][payloadHash];\n\n require(recovery != 0, RecoveryNotInitiated());\n require(recovery <= block.timestamp, RecoveryChallengePeriodNotEnded());\n\n delete recoveries[centrifugeId][adapter][payloadHash];\n _handle(centrifugeId, payload, adapter, true);\n emit ExecuteRecovery(centrifugeId, payload, adapter);\n }\n\n //----------------------------------------------------------------------------------------------\n // Outgoing\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IMessageSender\n function send(uint16 centrifugeId, bytes calldata message) external pauseable auth {\n require(message.length > 0, EmptyMessage());\n\n PoolId poolId = processor.messagePoolId(message);\n\n emit PrepareMessage(centrifugeId, poolId, message);\n\n if (isBatching) {\n bytes32 batchSlot = _outboundBatchSlot(centrifugeId, poolId);\n bytes memory previousMessage = TransientBytesLib.get(batchSlot);\n\n bytes32 gasLimitSlot = _gasLimitSlot(centrifugeId, poolId);\n uint128 newGasLimit = gasLimitSlot.tloadUint128() + gasService.gasLimit(centrifugeId, message);\n require(newGasLimit <= gasService.maxBatchSize(centrifugeId), ExceedsMaxBatchSize());\n gasLimitSlot.tstore(uint256(newGasLimit));\n\n if (previousMessage.length == 0) {\n TransientArrayLib.push(BATCH_LOCATORS_SLOT, _encodeLocator(centrifugeId, poolId));\n }\n\n TransientBytesLib.append(batchSlot, message);\n } else {\n _send(centrifugeId, poolId, message, gasService.gasLimit(centrifugeId, message));\n _refundTransaction();\n }\n }\n\n function _send(uint16 centrifugeId, PoolId poolId, bytes memory batch, uint128 batchGasLimit)\n internal\n returns (bool succeeded)\n {\n IAdapter[] memory adapters_ = adapters[centrifugeId];\n require(adapters[centrifugeId].length != 0, EmptyAdapterSet());\n\n SendData memory data = SendData({\n batchHash: keccak256(batch),\n payloadId: bytes32(\"\"),\n gasCost: new uint256[](MAX_ADAPTER_COUNT)\n });\n data.payloadId = keccak256(abi.encodePacked(localCentrifugeId, centrifugeId, data.batchHash));\n\n {\n // Estimate gas usage\n uint256 total;\n for (uint256 i; i < adapters_.length; i++) {\n data.gasCost[i] = adapters_[i].estimate(\n centrifugeId,\n i == PRIMARY_ADAPTER_ID - 1 ? batch : data.batchHash.serializeMessageProof(),\n batchGasLimit\n );\n\n total += data.gasCost[i];\n }\n\n // Ensure sufficient funds are available\n if (transactionRefund != address(0)) {\n require(total <= fuel, NotEnoughTransactionGas());\n fuel -= total;\n } else {\n if (total > subsidy[poolId].value) {\n _requestPoolFunding(poolId);\n }\n\n if (total <= subsidy[poolId].value) {\n subsidy[poolId].value -= uint96(total);\n } else {\n underpaid[centrifugeId][data.batchHash].counter++;\n underpaid[centrifugeId][data.batchHash].gasLimit = batchGasLimit;\n emit UnderpaidBatch(centrifugeId, batch);\n return false;\n }\n }\n }\n\n // Send batch and proofs\n for (uint256 j; j < adapters_.length; j++) {\n bytes32 adapterData = adapters_[j].send{value: data.gasCost[j]}(\n centrifugeId,\n j == PRIMARY_ADAPTER_ID - 1 ? batch : data.batchHash.serializeMessageProof(),\n batchGasLimit,\n transactionRefund != address(0) ? transactionRefund : address(subsidy[poolId].refund)\n );\n\n if (j == PRIMARY_ADAPTER_ID - 1) {\n emit SendBatch(\n centrifugeId,\n data.payloadId,\n batch,\n adapters_[j],\n adapterData,\n transactionRefund != address(0) ? transactionRefund : address(subsidy[poolId].refund)\n );\n } else {\n emit SendProof(\n centrifugeId,\n data.payloadId,\n data.batchHash,\n adapters_[j],\n adapterData\n );\n }\n }\n\n return true;\n }\n\n /// @inheritdoc IGateway\n function repay(uint16 centrifugeId, bytes memory batch) external payable pauseable {\n bytes32 batchHash = keccak256(batch);\n Underpaid storage underpaid_ = underpaid[centrifugeId][batchHash];\n require(underpaid_.counter > 0, NotUnderpaidBatch());\n\n PoolId poolId = processor.messagePoolId(batch);\n if (msg.value > 0) subsidizePool(poolId);\n\n require(_send(centrifugeId, poolId, batch, underpaid_.gasLimit), InsufficientFundsForRepayment());\n underpaid[centrifugeId][batchHash].counter--;\n\n emit RepayBatch(centrifugeId, batch);\n }\n\n function _refundTransaction() internal {\n if (transactionRefund == address(0)) return;\n\n // Reset before external call\n uint256 fuel_ = fuel;\n address transactionRefund_ = transactionRefund;\n fuel = 0;\n transactionRefund = address(0);\n\n if (fuel_ > 0) {\n (bool success,) = payable(transactionRefund_).call{value: fuel_}(new bytes(0));\n\n if (!success) {\n // If refund fails, move remaining fuel to global pot\n _subsidizePool(GLOBAL_POT, transactionRefund_, fuel_);\n }\n }\n }\n\n function _requestPoolFunding(PoolId poolId) internal {\n IRecoverable refund = subsidy[poolId].refund;\n if (!poolId.isNull() && address(refund) != address(0)) {\n uint256 refundBalance = address(refund).balance;\n if (refundBalance == 0) return;\n\n // Send to the gateway GLOBAL_POT\n refund.recoverTokens(ETH_ADDRESS, address(this), refundBalance);\n\n // Extract from the GLOBAL_POT\n subsidy[GLOBAL_POT].value -= uint96(refundBalance);\n _subsidizePool(poolId, address(refund), refundBalance);\n }\n }\n\n /// @inheritdoc IGateway\n function setRefundAddress(PoolId poolId, IRecoverable refund) public auth {\n subsidy[poolId].refund = refund;\n emit SetRefundAddress(poolId, refund);\n }\n\n /// @inheritdoc IGateway\n function subsidizePool(PoolId poolId) public payable {\n require(address(subsidy[poolId].refund) != address(0), RefundAddressNotSet());\n _subsidizePool(poolId, msg.sender, msg.value);\n }\n\n function _subsidizePool(PoolId poolId, address who, uint256 value) internal {\n subsidy[poolId].value += uint96(value);\n emit SubsidizePool(poolId, who, value);\n }\n\n /// @inheritdoc IGateway\n function payTransaction(address payer) external payable auth {\n transactionRefund = payer;\n fuel += msg.value;\n }\n\n /// @inheritdoc IGateway\n function startBatching() external auth {\n isBatching = true;\n }\n\n /// @inheritdoc IGateway\n function endBatching() external auth {\n require(isBatching, NoBatched());\n\n bytes32[] memory locators = TransientArrayLib.getBytes32(BATCH_LOCATORS_SLOT);\n for (uint256 i; i < locators.length; i++) {\n (uint16 centrifugeId, PoolId poolId) = _parseLocator(locators[i]);\n bytes32 outboundBatchSlot = _outboundBatchSlot(centrifugeId, poolId);\n uint128 gasLimit = _gasLimitSlot(centrifugeId, poolId).tloadUint128();\n\n _send(centrifugeId, poolId, TransientBytesLib.get(outboundBatchSlot), gasLimit);\n\n TransientBytesLib.clear(outboundBatchSlot);\n _gasLimitSlot(centrifugeId, poolId).tstore(uint256(0));\n }\n\n TransientArrayLib.clear(BATCH_LOCATORS_SLOT);\n isBatching = false;\n\n _refundTransaction();\n }\n\n function _encodeLocator(uint16 centrifugeId, PoolId poolId) internal pure returns (bytes32) {\n return bytes32(abi.encodePacked(bytes2(centrifugeId), bytes8(poolId.raw())));\n }\n\n function _parseLocator(bytes32 locator) internal pure returns (uint16 centrifugeId, PoolId poolId) {\n centrifugeId = uint16(bytes2(locator));\n poolId = PoolId.wrap(uint64(bytes8(locator << 16)));\n }\n\n function _gasLimitSlot(uint16 centrifugeId, PoolId poolId) internal pure returns (bytes32) {\n return keccak256(abi.encode(\"batchGasLimit\", centrifugeId, poolId));\n }\n\n function _outboundBatchSlot(uint16 centrifugeId, PoolId poolId) internal pure returns (bytes32) {\n return keccak256(abi.encode(\"outboundBatch\", centrifugeId, poolId));\n }\n\n //----------------------------------------------------------------------------------------------\n // View methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IGateway\n function estimate(uint16 centrifugeId, bytes calldata payload) external view returns (uint256 total) {\n bytes memory proof = keccak256(payload).serializeMessageProof();\n\n uint256 gasLimit = 0;\n for (uint256 pos; pos < payload.length;) {\n bytes calldata inner = payload[pos:payload.length];\n gasLimit += gasService.gasLimit(centrifugeId, inner);\n pos += processor.messageLength(inner);\n }\n\n uint256 adaptersCount = adapters[centrifugeId].length;\n for (uint256 i; i < adaptersCount; i++) {\n bytes memory message = i == PRIMARY_ADAPTER_ID - 1 ? payload : proof;\n total += IAdapter(adapters[centrifugeId][i]).estimate(centrifugeId, message, gasLimit);\n }\n }\n\n /// @inheritdoc IGateway\n function quorum(uint16 centrifugeId) external view returns (uint8) {\n Adapter memory adapter = _activeAdapters[centrifugeId][adapters[centrifugeId][0]];\n return adapter.quorum;\n }\n\n /// @inheritdoc IGateway\n function activeSessionId(uint16 centrifugeId) external view returns (uint64) {\n Adapter memory adapter = _activeAdapters[centrifugeId][adapters[centrifugeId][0]];\n return adapter.activeSessionId;\n }\n\n /// @inheritdoc IGateway\n function votes(uint16 centrifugeId, bytes32 batchHash) external view returns (uint16[MAX_ADAPTER_COUNT] memory) {\n return inboundBatch[centrifugeId][batchHash].votes;\n }\n}\n\n" + }, + "src/common/Guardian.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {IRoot} from \"src/common/interfaces/IRoot.sol\";\nimport {IAdapter} from \"src/common/interfaces/IAdapter.sol\";\nimport {IGuardian, ISafe} from \"src/common/interfaces/IGuardian.sol\";\nimport {IRootMessageSender} from \"src/common/interfaces/IGatewaySenders.sol\";\nimport {IHubGuardianActions} from \"src/common/interfaces/IGuardianActions.sol\";\n\ncontract Guardian is IGuardian {\n using CastLib for address;\n\n IRoot public immutable root;\n\n IHubGuardianActions public hub;\n ISafe public safe;\n IRootMessageSender public sender;\n\n constructor(ISafe safe_, IRoot root_, IRootMessageSender messageDispatcher_) {\n root = root_;\n safe = safe_;\n sender = messageDispatcher_;\n }\n\n modifier onlySafe() {\n require(msg.sender == address(safe), NotTheAuthorizedSafe());\n _;\n }\n\n modifier onlySafeOrOwner() {\n require(msg.sender == address(safe) || _isSafeOwner(msg.sender), NotTheAuthorizedSafeOrItsOwner());\n _;\n }\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IGuardian\n function file(bytes32 what, address data) external onlySafe {\n if (what == \"safe\") safe = ISafe(data);\n else if (what == \"sender\") sender = IRootMessageSender(data);\n else if (what == \"hub\") hub = IHubGuardianActions(data);\n else revert FileUnrecognizedParam();\n\n emit File(what, data);\n }\n\n //----------------------------------------------------------------------------------------------\n // Admin actions\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IGuardian\n function createPool(PoolId poolId, address admin, AssetId currency) external onlySafe {\n return hub.createPool(poolId, admin, currency);\n }\n\n /// @inheritdoc IGuardian\n function pause() external onlySafeOrOwner {\n root.pause();\n }\n\n /// @inheritdoc IGuardian\n function unpause() external onlySafe {\n root.unpause();\n }\n\n /// @inheritdoc IGuardian\n function scheduleRely(address target) external onlySafe {\n root.scheduleRely(target);\n }\n\n /// @inheritdoc IGuardian\n function cancelRely(address target) external onlySafe {\n root.cancelRely(target);\n }\n\n /// @inheritdoc IGuardian\n function scheduleUpgrade(uint16 centrifugeId, address target) external onlySafe {\n sender.sendScheduleUpgrade(centrifugeId, target.toBytes32());\n }\n\n /// @inheritdoc IGuardian\n function cancelUpgrade(uint16 centrifugeId, address target) external onlySafe {\n sender.sendCancelUpgrade(centrifugeId, target.toBytes32());\n }\n\n /// @inheritdoc IGuardian\n function recoverTokens(\n uint16 centrifugeId,\n address target,\n address token,\n uint256 tokenId,\n address to,\n uint256 amount\n ) external onlySafe {\n sender.sendRecoverTokens(centrifugeId, target.toBytes32(), token.toBytes32(), tokenId, to.toBytes32(), amount);\n }\n\n /// @inheritdoc IGuardian\n function initiateRecovery(uint16 centrifugeId, uint16 adapterCentrifugeId, IAdapter adapter, bytes32 hash)\n external\n onlySafe\n {\n sender.sendInitiateRecovery(centrifugeId, adapterCentrifugeId, address(adapter).toBytes32(), hash);\n }\n\n /// @inheritdoc IGuardian\n function disputeRecovery(uint16 centrifugeId, uint16 adapterCentrifugeId, IAdapter adapter, bytes32 hash)\n external\n onlySafe\n {\n sender.sendDisputeRecovery(centrifugeId, adapterCentrifugeId, address(adapter).toBytes32(), hash);\n }\n\n //----------------------------------------------------------------------------------------------\n // Helpers\n //----------------------------------------------------------------------------------------------\n\n function _isSafeOwner(address addr) internal view returns (bool) {\n try safe.isOwner(addr) returns (bool isOwner) {\n return isOwner;\n } catch {\n return false;\n }\n }\n}\n" + }, + "src/common/MessageDispatcher.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {D18, d18} from \"src/misc/types/D18.sol\";\nimport {IRecoverable} from \"src/misc/interfaces/IRecoverable.sol\";\n\nimport {MessageLib} from \"src/common/libraries/MessageLib.sol\";\nimport {IAdapter} from \"src/common/interfaces/IAdapter.sol\";\nimport {IGateway} from \"src/common/interfaces/IGateway.sol\";\nimport {IRoot} from \"src/common/interfaces/IRoot.sol\";\nimport {\n IRequestManagerGatewayHandler,\n IPoolManagerGatewayHandler,\n IBalanceSheetGatewayHandler,\n IHubGatewayHandler\n} from \"src/common/interfaces/IGatewayHandlers.sol\";\nimport {IVaultMessageSender, IPoolMessageSender, IRootMessageSender} from \"src/common/interfaces/IGatewaySenders.sol\";\n\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {IMessageDispatcher} from \"src/common/interfaces/IMessageDispatcher.sol\";\nimport {ITokenRecoverer} from \"src/common/interfaces/ITokenRecoverer.sol\";\n\ncontract MessageDispatcher is Auth, IMessageDispatcher {\n using CastLib for *;\n using MessageLib for *;\n using BytesLib for bytes;\n using MathLib for uint256;\n\n IRoot public immutable root;\n IGateway public immutable gateway;\n ITokenRecoverer public immutable tokenRecoverer;\n\n uint16 public immutable localCentrifugeId;\n\n IHubGatewayHandler public hub;\n IPoolManagerGatewayHandler public poolManager;\n IRequestManagerGatewayHandler public investmentManager;\n IBalanceSheetGatewayHandler public balanceSheet;\n\n constructor(\n uint16 localCentrifugeId_,\n IRoot root_,\n IGateway gateway_,\n ITokenRecoverer tokenRecoverer_,\n address deployer\n ) Auth(deployer) {\n localCentrifugeId = localCentrifugeId_;\n root = root_;\n gateway = gateway_;\n tokenRecoverer = tokenRecoverer_;\n }\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IMessageDispatcher\n function file(bytes32 what, address data) external auth {\n if (what == \"hub\") hub = IHubGatewayHandler(data);\n else if (what == \"poolManager\") poolManager = IPoolManagerGatewayHandler(data);\n else if (what == \"investmentManager\") investmentManager = IRequestManagerGatewayHandler(data);\n else if (what == \"balanceSheet\") balanceSheet = IBalanceSheetGatewayHandler(data);\n else revert FileUnrecognizedParam();\n\n emit File(what, data);\n }\n\n //----------------------------------------------------------------------------------------------\n // Helpers\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IMessageDispatcher\n function estimate(uint16 centrifugeId, bytes calldata payload) external view returns (uint256 amount) {\n if (centrifugeId == localCentrifugeId) return 0;\n return gateway.estimate(centrifugeId, payload);\n }\n\n //----------------------------------------------------------------------------------------------\n // Outgoing\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IPoolMessageSender\n function sendNotifyPool(uint16 centrifugeId, PoolId poolId) external auth {\n if (centrifugeId == localCentrifugeId) {\n poolManager.addPool(poolId);\n } else {\n gateway.send(centrifugeId, MessageLib.NotifyPool({poolId: poolId.raw()}).serialize());\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendNotifyShareClass(\n uint16 centrifugeId,\n PoolId poolId,\n ShareClassId scId,\n string memory name,\n string memory symbol,\n uint8 decimals,\n bytes32 salt,\n bytes32 hook\n ) external auth {\n if (centrifugeId == localCentrifugeId) {\n poolManager.addShareClass(poolId, scId, name, symbol, decimals, salt, hook.toAddress());\n } else {\n gateway.send(\n centrifugeId,\n MessageLib.NotifyShareClass({\n poolId: poolId.raw(),\n scId: scId.raw(),\n name: name,\n symbol: symbol.toBytes32(),\n decimals: decimals,\n salt: salt,\n hook: hook\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendNotifyShareMetadata(\n uint16 centrifugeId,\n PoolId poolId,\n ShareClassId scId,\n string memory name,\n string memory symbol\n ) external auth {\n if (centrifugeId == localCentrifugeId) {\n poolManager.updateShareMetadata(poolId, scId, name, symbol);\n } else {\n gateway.send(\n centrifugeId,\n MessageLib.NotifyShareMetadata({\n poolId: poolId.raw(),\n scId: scId.raw(),\n name: name,\n symbol: symbol.toBytes32()\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendUpdateShareHook(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bytes32 hook) external auth {\n if (centrifugeId == localCentrifugeId) {\n poolManager.updateShareHook(poolId, scId, hook.toAddress());\n } else {\n gateway.send(\n centrifugeId,\n MessageLib.UpdateShareHook({poolId: poolId.raw(), scId: scId.raw(), hook: hook}).serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendNotifyPricePoolPerShare(uint16 chainId, PoolId poolId, ShareClassId scId, D18 sharePrice)\n external\n auth\n {\n uint64 timestamp = block.timestamp.toUint64();\n if (chainId == localCentrifugeId) {\n poolManager.updatePricePoolPerShare(poolId, scId, sharePrice.raw(), timestamp);\n } else {\n gateway.send(\n chainId,\n MessageLib.NotifyPricePoolPerShare({\n poolId: poolId.raw(),\n scId: scId.raw(),\n price: sharePrice.raw(),\n timestamp: timestamp\n }).serialize()\n );\n }\n }\n\n function sendNotifyPricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId, D18 price) external auth {\n uint64 timestamp = block.timestamp.toUint64();\n if (assetId.centrifugeId() == localCentrifugeId) {\n poolManager.updatePricePoolPerAsset(poolId, scId, assetId, price.raw(), timestamp);\n } else {\n gateway.send(\n assetId.centrifugeId(),\n MessageLib.NotifyPricePoolPerAsset({\n poolId: poolId.raw(),\n scId: scId.raw(),\n assetId: assetId.raw(),\n price: price.raw(),\n timestamp: timestamp\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendFulfilledDepositRequest(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n bytes32 investor,\n uint128 assetAmount,\n uint128 shareAmount\n ) external auth {\n if (assetId.centrifugeId() == localCentrifugeId) {\n investmentManager.fulfillDepositRequest(\n poolId, scId, investor.toAddress(), assetId, assetAmount, shareAmount\n );\n } else {\n gateway.send(\n assetId.centrifugeId(),\n MessageLib.FulfilledDepositRequest({\n poolId: poolId.raw(),\n scId: scId.raw(),\n investor: investor,\n assetId: assetId.raw(),\n assetAmount: assetAmount,\n shareAmount: shareAmount\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendFulfilledRedeemRequest(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n bytes32 investor,\n uint128 assetAmount,\n uint128 shareAmount\n ) external auth {\n if (assetId.centrifugeId() == localCentrifugeId) {\n investmentManager.fulfillRedeemRequest(\n poolId, scId, investor.toAddress(), assetId, assetAmount, shareAmount\n );\n } else {\n gateway.send(\n assetId.centrifugeId(),\n MessageLib.FulfilledRedeemRequest({\n poolId: poolId.raw(),\n scId: scId.raw(),\n investor: investor,\n assetId: assetId.raw(),\n assetAmount: assetAmount,\n shareAmount: shareAmount\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendFulfilledCancelDepositRequest(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n bytes32 investor,\n uint128 cancelledAmount\n ) external auth {\n if (assetId.centrifugeId() == localCentrifugeId) {\n investmentManager.fulfillCancelDepositRequest(\n poolId, scId, investor.toAddress(), assetId, cancelledAmount, cancelledAmount\n );\n } else {\n gateway.send(\n assetId.centrifugeId(),\n MessageLib.FulfilledCancelDepositRequest({\n poolId: poolId.raw(),\n scId: scId.raw(),\n investor: investor,\n assetId: assetId.raw(),\n cancelledAmount: cancelledAmount\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendFulfilledCancelRedeemRequest(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n bytes32 investor,\n uint128 cancelledShares\n ) external auth {\n if (assetId.centrifugeId() == localCentrifugeId) {\n investmentManager.fulfillCancelRedeemRequest(poolId, scId, investor.toAddress(), assetId, cancelledShares);\n } else {\n gateway.send(\n assetId.centrifugeId(),\n MessageLib.FulfilledCancelRedeemRequest({\n poolId: poolId.raw(),\n scId: scId.raw(),\n investor: investor,\n assetId: assetId.raw(),\n cancelledShares: cancelledShares\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendUpdateRestriction(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bytes calldata payload)\n external\n auth\n {\n if (centrifugeId == localCentrifugeId) {\n poolManager.updateRestriction(poolId, scId, payload);\n } else {\n gateway.send(\n centrifugeId,\n MessageLib.UpdateRestriction({poolId: poolId.raw(), scId: scId.raw(), payload: payload}).serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendUpdateContract(\n uint16 centrifugeId,\n PoolId poolId,\n ShareClassId scId,\n bytes32 target,\n bytes calldata payload\n ) external auth {\n if (centrifugeId == localCentrifugeId) {\n poolManager.updateContract(poolId, scId, target.toAddress(), payload);\n } else {\n gateway.send(\n centrifugeId,\n MessageLib.UpdateContract({poolId: poolId.raw(), scId: scId.raw(), target: target, payload: payload})\n .serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendApprovedDeposits(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n uint128 assetAmount,\n D18 pricePoolPerAsset\n ) external auth {\n if (assetId.centrifugeId() == localCentrifugeId) {\n investmentManager.approvedDeposits(poolId, scId, assetId, assetAmount, pricePoolPerAsset);\n } else {\n gateway.send(\n assetId.centrifugeId(),\n MessageLib.ApprovedDeposits({\n poolId: poolId.raw(),\n scId: scId.raw(),\n assetId: assetId.raw(),\n assetAmount: assetAmount,\n pricePoolPerAsset: pricePoolPerAsset.raw()\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendIssuedShares(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n uint128 shareAmount,\n D18 pricePoolPerShare\n ) external auth {\n if (assetId.centrifugeId() == localCentrifugeId) {\n investmentManager.issuedShares(poolId, scId, shareAmount, pricePoolPerShare);\n } else {\n gateway.send(\n assetId.centrifugeId(),\n MessageLib.IssuedShares({\n poolId: poolId.raw(),\n scId: scId.raw(),\n shareAmount: shareAmount,\n pricePoolPerShare: pricePoolPerShare.raw()\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendRevokedShares(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n uint128 assetAmount,\n uint128 shareAmount,\n D18 pricePoolPerShare\n ) external auth {\n if (assetId.centrifugeId() == localCentrifugeId) {\n investmentManager.revokedShares(poolId, scId, assetId, assetAmount, shareAmount, pricePoolPerShare);\n } else {\n gateway.send(\n assetId.centrifugeId(),\n MessageLib.RevokedShares({\n poolId: poolId.raw(),\n scId: scId.raw(),\n assetId: assetId.raw(),\n assetAmount: assetAmount,\n shareAmount: shareAmount,\n pricePoolPerShare: pricePoolPerShare.raw()\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendTriggerIssueShares(uint16 centrifugeId, PoolId poolId, ShareClassId scId, address who, uint128 shares)\n external\n auth\n {\n if (centrifugeId == localCentrifugeId) {\n balanceSheet.triggerIssueShares(poolId, scId, who, shares);\n } else {\n gateway.send(\n centrifugeId,\n MessageLib.TriggerIssueShares({\n poolId: poolId.raw(),\n scId: scId.raw(),\n who: who.toBytes32(),\n shares: shares\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendTriggerSubmitQueuedShares(uint16 centrifugeId, PoolId poolId, ShareClassId scId) external auth {\n if (centrifugeId == localCentrifugeId) {\n balanceSheet.submitQueuedShares(poolId, scId);\n } else {\n gateway.send(\n centrifugeId, MessageLib.TriggerSubmitQueuedShares({poolId: poolId.raw(), scId: scId.raw()}).serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendTriggerSubmitQueuedAssets(PoolId poolId, ShareClassId scId, AssetId assetId) external auth {\n if (assetId.centrifugeId() == localCentrifugeId) {\n balanceSheet.submitQueuedAssets(poolId, scId, assetId);\n } else {\n gateway.send(\n assetId.centrifugeId(),\n MessageLib.TriggerSubmitQueuedAssets({poolId: poolId.raw(), scId: scId.raw(), assetId: assetId.raw()})\n .serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendSetQueue(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bool enabled) external auth {\n if (centrifugeId == localCentrifugeId) {\n balanceSheet.setQueue(poolId, scId, enabled);\n } else {\n gateway.send(\n centrifugeId,\n MessageLib.SetQueue({poolId: poolId.raw(), scId: scId.raw(), enabled: enabled}).serialize()\n );\n }\n }\n\n /// @inheritdoc IRootMessageSender\n function sendScheduleUpgrade(uint16 centrifugeId, bytes32 target) external auth {\n if (centrifugeId == localCentrifugeId) {\n root.scheduleRely(target.toAddress());\n } else {\n gateway.send(centrifugeId, MessageLib.ScheduleUpgrade({target: target}).serialize());\n }\n }\n\n /// @inheritdoc IRootMessageSender\n function sendCancelUpgrade(uint16 centrifugeId, bytes32 target) external auth {\n if (centrifugeId == localCentrifugeId) {\n root.cancelRely(target.toAddress());\n } else {\n gateway.send(centrifugeId, MessageLib.CancelUpgrade({target: target}).serialize());\n }\n }\n\n /// @inheritdoc IRootMessageSender\n function sendRecoverTokens(\n uint16 centrifugeId,\n bytes32 target,\n bytes32 token,\n uint256 tokenId,\n bytes32 to,\n uint256 amount\n ) external auth {\n if (centrifugeId == localCentrifugeId) {\n tokenRecoverer.recoverTokens(\n IRecoverable(target.toAddress()), token.toAddress(), tokenId, to.toAddress(), amount\n );\n } else {\n gateway.send(\n centrifugeId,\n MessageLib.RecoverTokens({target: target, token: token, tokenId: tokenId, to: to, amount: amount})\n .serialize()\n );\n }\n }\n\n /// @inheritdoc IRootMessageSender\n function sendInitiateRecovery(uint16 centrifugeId, uint16 adapterCentrifugeId, bytes32 adapter, bytes32 hash)\n external\n auth\n {\n if (centrifugeId == localCentrifugeId) {\n gateway.initiateRecovery(adapterCentrifugeId, IAdapter(adapter.toAddress()), hash);\n } else {\n gateway.send(\n centrifugeId,\n MessageLib.InitiateRecovery({hash: hash, adapter: adapter, centrifugeId: adapterCentrifugeId}).serialize(\n )\n );\n }\n }\n\n /// @inheritdoc IRootMessageSender\n function sendDisputeRecovery(uint16 centrifugeId, uint16 adapterCentrifugeId, bytes32 adapter, bytes32 hash)\n external\n auth\n {\n if (centrifugeId == localCentrifugeId) {\n gateway.disputeRecovery(adapterCentrifugeId, IAdapter(adapter.toAddress()), hash);\n } else {\n gateway.send(\n centrifugeId,\n MessageLib.DisputeRecovery({hash: hash, adapter: adapter, centrifugeId: adapterCentrifugeId}).serialize(\n )\n );\n }\n }\n\n /// @inheritdoc IVaultMessageSender\n function sendTransferShares(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bytes32 receiver, uint128 amount)\n external\n auth\n {\n if (centrifugeId == localCentrifugeId) {\n poolManager.handleTransferShares(poolId, scId, receiver.toAddress(), amount);\n } else {\n gateway.send(\n centrifugeId,\n MessageLib.TransferShares({poolId: poolId.raw(), scId: scId.raw(), receiver: receiver, amount: amount})\n .serialize()\n );\n }\n }\n\n /// @inheritdoc IVaultMessageSender\n function sendDepositRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId assetId, uint128 amount)\n external\n auth\n {\n if (poolId.centrifugeId() == localCentrifugeId) {\n hub.depositRequest(poolId, scId, investor, assetId, amount);\n } else {\n gateway.send(\n poolId.centrifugeId(),\n MessageLib.DepositRequest({\n poolId: poolId.raw(),\n scId: scId.raw(),\n investor: investor,\n assetId: assetId.raw(),\n amount: amount\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IVaultMessageSender\n function sendRedeemRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId assetId, uint128 amount)\n external\n auth\n {\n if (poolId.centrifugeId() == localCentrifugeId) {\n hub.redeemRequest(poolId, scId, investor, assetId, amount);\n } else {\n gateway.send(\n poolId.centrifugeId(),\n MessageLib.RedeemRequest({\n poolId: poolId.raw(),\n scId: scId.raw(),\n investor: investor,\n assetId: assetId.raw(),\n amount: amount\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IVaultMessageSender\n function sendCancelDepositRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId assetId)\n external\n auth\n {\n if (poolId.centrifugeId() == localCentrifugeId) {\n hub.cancelDepositRequest(poolId, scId, investor, assetId);\n } else {\n gateway.send(\n poolId.centrifugeId(),\n MessageLib.CancelDepositRequest({\n poolId: poolId.raw(),\n scId: scId.raw(),\n investor: investor,\n assetId: assetId.raw()\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IVaultMessageSender\n function sendCancelRedeemRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId assetId)\n external\n auth\n {\n if (poolId.centrifugeId() == localCentrifugeId) {\n hub.cancelRedeemRequest(poolId, scId, investor, assetId);\n } else {\n gateway.send(\n poolId.centrifugeId(),\n MessageLib.CancelRedeemRequest({\n poolId: poolId.raw(),\n scId: scId.raw(),\n investor: investor,\n assetId: assetId.raw()\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IVaultMessageSender\n function sendUpdateHoldingAmount(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n address provider,\n uint128 amount,\n D18 pricePoolPerAsset,\n bool isIncrease\n ) external auth {\n if (poolId.centrifugeId() == localCentrifugeId) {\n hub.updateHoldingAmount(poolId, scId, assetId, amount, pricePoolPerAsset, isIncrease);\n } else {\n gateway.send(\n poolId.centrifugeId(),\n MessageLib.UpdateHoldingAmount({\n poolId: poolId.raw(),\n scId: scId.raw(),\n assetId: assetId.raw(),\n who: provider.toBytes32(),\n amount: amount,\n pricePerUnit: pricePoolPerAsset.raw(),\n timestamp: uint64(block.timestamp),\n isIncrease: isIncrease\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IVaultMessageSender\n function sendUpdateShares(PoolId poolId, ShareClassId scId, uint128 shares, bool isIssuance) external auth {\n if (poolId.centrifugeId() == localCentrifugeId) {\n if (isIssuance) {\n hub.increaseShareIssuance(poolId, scId, shares);\n } else {\n hub.decreaseShareIssuance(poolId, scId, shares);\n }\n } else {\n gateway.send(\n poolId.centrifugeId(),\n MessageLib.UpdateShares({\n poolId: poolId.raw(),\n scId: scId.raw(),\n shares: shares,\n timestamp: uint64(block.timestamp),\n isIssuance: isIssuance\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IVaultMessageSender\n function sendRegisterAsset(uint16 centrifugeId, AssetId assetId, uint8 decimals) external auth {\n if (centrifugeId == localCentrifugeId) {\n hub.registerAsset(assetId, decimals);\n } else {\n gateway.send(\n centrifugeId, MessageLib.RegisterAsset({assetId: assetId.raw(), decimals: decimals}).serialize()\n );\n }\n }\n}\n" + }, + "src/common/MessageProcessor.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {D18, d18} from \"src/misc/types/D18.sol\";\nimport {IRecoverable} from \"src/misc/interfaces/IRecoverable.sol\";\n\nimport {MessageType, MessageLib} from \"src/common/libraries/MessageLib.sol\";\nimport {IAdapter} from \"src/common/interfaces/IAdapter.sol\";\nimport {IMessageHandler} from \"src/common/interfaces/IMessageHandler.sol\";\nimport {IMessageProcessor} from \"src/common/interfaces/IMessageProcessor.sol\";\nimport {IMessageProperties} from \"src/common/interfaces/IMessageProperties.sol\";\nimport {IRoot} from \"src/common/interfaces/IRoot.sol\";\nimport {\n IGatewayHandler,\n IPoolManagerGatewayHandler,\n IBalanceSheetGatewayHandler,\n IHubGatewayHandler,\n IRequestManagerGatewayHandler\n} from \"src/common/interfaces/IGatewayHandlers.sol\";\n\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ITokenRecoverer} from \"src/common/interfaces/ITokenRecoverer.sol\";\n\ncontract MessageProcessor is Auth, IMessageProcessor {\n using CastLib for *;\n using MessageLib for *;\n using BytesLib for bytes;\n\n IRoot public immutable root;\n ITokenRecoverer public immutable tokenRecoverer;\n\n IGatewayHandler public gateway;\n IHubGatewayHandler public hub;\n IPoolManagerGatewayHandler public poolManager;\n IRequestManagerGatewayHandler public investmentManager;\n IBalanceSheetGatewayHandler public balanceSheet;\n\n constructor(IRoot root_, ITokenRecoverer tokenRecoverer_, address deployer) Auth(deployer) {\n root = root_;\n tokenRecoverer = tokenRecoverer_;\n }\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IMessageProcessor\n function file(bytes32 what, address data) external auth {\n if (what == \"gateway\") gateway = IGatewayHandler(data);\n else if (what == \"hub\") hub = IHubGatewayHandler(data);\n else if (what == \"poolManager\") poolManager = IPoolManagerGatewayHandler(data);\n else if (what == \"investmentManager\") investmentManager = IRequestManagerGatewayHandler(data);\n else if (what == \"balanceSheet\") balanceSheet = IBalanceSheetGatewayHandler(data);\n else revert FileUnrecognizedParam();\n\n emit File(what, data);\n }\n\n //----------------------------------------------------------------------------------------------\n // Handlers\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IMessageHandler\n function handle(uint16, bytes calldata message) external auth {\n MessageType kind = message.messageType();\n\n if (kind == MessageType.InitiateRecovery) {\n MessageLib.InitiateRecovery memory m = message.deserializeInitiateRecovery();\n gateway.initiateRecovery(m.centrifugeId, IAdapter(m.adapter.toAddress()), m.hash);\n } else if (kind == MessageType.DisputeRecovery) {\n MessageLib.DisputeRecovery memory m = message.deserializeDisputeRecovery();\n gateway.disputeRecovery(m.centrifugeId, IAdapter(m.adapter.toAddress()), m.hash);\n } else if (kind == MessageType.ScheduleUpgrade) {\n MessageLib.ScheduleUpgrade memory m = message.deserializeScheduleUpgrade();\n root.scheduleRely(m.target.toAddress());\n } else if (kind == MessageType.CancelUpgrade) {\n MessageLib.CancelUpgrade memory m = message.deserializeCancelUpgrade();\n root.cancelRely(m.target.toAddress());\n } else if (kind == MessageType.RecoverTokens) {\n MessageLib.RecoverTokens memory m = message.deserializeRecoverTokens();\n tokenRecoverer.recoverTokens(\n IRecoverable(m.target.toAddress()), m.token.toAddress(), m.tokenId, m.to.toAddress(), m.amount\n );\n } else if (kind == MessageType.RegisterAsset) {\n MessageLib.RegisterAsset memory m = message.deserializeRegisterAsset();\n hub.registerAsset(AssetId.wrap(m.assetId), m.decimals);\n } else if (kind == MessageType.NotifyPool) {\n poolManager.addPool(PoolId.wrap(MessageLib.deserializeNotifyPool(message).poolId));\n } else if (kind == MessageType.NotifyShareClass) {\n MessageLib.NotifyShareClass memory m = MessageLib.deserializeNotifyShareClass(message);\n poolManager.addShareClass(\n PoolId.wrap(m.poolId),\n ShareClassId.wrap(m.scId),\n m.name,\n m.symbol.toString(),\n m.decimals,\n m.salt,\n m.hook.toAddress()\n );\n } else if (kind == MessageType.NotifyPricePoolPerShare) {\n MessageLib.NotifyPricePoolPerShare memory m = MessageLib.deserializeNotifyPricePoolPerShare(message);\n poolManager.updatePricePoolPerShare(PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.price, m.timestamp);\n } else if (kind == MessageType.NotifyPricePoolPerAsset) {\n MessageLib.NotifyPricePoolPerAsset memory m = MessageLib.deserializeNotifyPricePoolPerAsset(message);\n poolManager.updatePricePoolPerAsset(\n PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), AssetId.wrap(m.assetId), m.price, m.timestamp\n );\n } else if (kind == MessageType.NotifyShareMetadata) {\n MessageLib.NotifyShareMetadata memory m = MessageLib.deserializeNotifyShareMetadata(message);\n poolManager.updateShareMetadata(\n PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.name, m.symbol.toString()\n );\n } else if (kind == MessageType.UpdateShareHook) {\n MessageLib.UpdateShareHook memory m = MessageLib.deserializeUpdateShareHook(message);\n poolManager.updateShareHook(PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.hook.toAddress());\n } else if (kind == MessageType.TransferShares) {\n MessageLib.TransferShares memory m = MessageLib.deserializeTransferShares(message);\n poolManager.handleTransferShares(\n PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.receiver.toAddress(), m.amount\n );\n } else if (kind == MessageType.UpdateRestriction) {\n MessageLib.UpdateRestriction memory m = MessageLib.deserializeUpdateRestriction(message);\n poolManager.updateRestriction(PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.payload);\n } else if (kind == MessageType.UpdateContract) {\n MessageLib.UpdateContract memory m = MessageLib.deserializeUpdateContract(message);\n poolManager.updateContract(\n PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.target.toAddress(), m.payload\n );\n } else if (kind == MessageType.DepositRequest) {\n MessageLib.DepositRequest memory m = message.deserializeDepositRequest();\n hub.depositRequest(\n PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.investor, AssetId.wrap(m.assetId), m.amount\n );\n } else if (kind == MessageType.RedeemRequest) {\n MessageLib.RedeemRequest memory m = message.deserializeRedeemRequest();\n hub.redeemRequest(\n PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.investor, AssetId.wrap(m.assetId), m.amount\n );\n } else if (kind == MessageType.CancelDepositRequest) {\n MessageLib.CancelDepositRequest memory m = message.deserializeCancelDepositRequest();\n hub.cancelDepositRequest(\n PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.investor, AssetId.wrap(m.assetId)\n );\n } else if (kind == MessageType.CancelRedeemRequest) {\n MessageLib.CancelRedeemRequest memory m = message.deserializeCancelRedeemRequest();\n hub.cancelRedeemRequest(\n PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.investor, AssetId.wrap(m.assetId)\n );\n } else if (kind == MessageType.FulfilledDepositRequest) {\n MessageLib.FulfilledDepositRequest memory m = message.deserializeFulfilledDepositRequest();\n investmentManager.fulfillDepositRequest(\n PoolId.wrap(m.poolId),\n ShareClassId.wrap(m.scId),\n m.investor.toAddress(),\n AssetId.wrap(m.assetId),\n m.assetAmount,\n m.shareAmount\n );\n } else if (kind == MessageType.FulfilledRedeemRequest) {\n MessageLib.FulfilledRedeemRequest memory m = message.deserializeFulfilledRedeemRequest();\n investmentManager.fulfillRedeemRequest(\n PoolId.wrap(m.poolId),\n ShareClassId.wrap(m.scId),\n m.investor.toAddress(),\n AssetId.wrap(m.assetId),\n m.assetAmount,\n m.shareAmount\n );\n } else if (kind == MessageType.FulfilledCancelDepositRequest) {\n MessageLib.FulfilledCancelDepositRequest memory m = message.deserializeFulfilledCancelDepositRequest();\n investmentManager.fulfillCancelDepositRequest(\n PoolId.wrap(m.poolId),\n ShareClassId.wrap(m.scId),\n m.investor.toAddress(),\n AssetId.wrap(m.assetId),\n m.cancelledAmount,\n m.cancelledAmount\n );\n } else if (kind == MessageType.FulfilledCancelRedeemRequest) {\n MessageLib.FulfilledCancelRedeemRequest memory m = message.deserializeFulfilledCancelRedeemRequest();\n investmentManager.fulfillCancelRedeemRequest(\n PoolId.wrap(m.poolId),\n ShareClassId.wrap(m.scId),\n m.investor.toAddress(),\n AssetId.wrap(m.assetId),\n m.cancelledShares\n );\n } else if (kind == MessageType.TriggerIssueShares) {\n MessageLib.TriggerIssueShares memory m = message.deserializeTriggerIssueShares();\n balanceSheet.triggerIssueShares(\n PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.who.toAddress(), m.shares\n );\n } else if (kind == MessageType.UpdateHoldingAmount) {\n MessageLib.UpdateHoldingAmount memory m = message.deserializeUpdateHoldingAmount();\n hub.updateHoldingAmount(\n PoolId.wrap(m.poolId),\n ShareClassId.wrap(m.scId),\n AssetId.wrap(m.assetId),\n m.amount,\n D18.wrap(m.pricePerUnit),\n m.isIncrease\n );\n } else if (kind == MessageType.UpdateShares) {\n MessageLib.UpdateShares memory m = message.deserializeUpdateShares();\n if (m.isIssuance) {\n hub.increaseShareIssuance(PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.shares);\n } else {\n hub.decreaseShareIssuance(PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.shares);\n }\n } else if (kind == MessageType.ApprovedDeposits) {\n MessageLib.ApprovedDeposits memory m = message.deserializeApprovedDeposits();\n investmentManager.approvedDeposits(\n PoolId.wrap(m.poolId),\n ShareClassId.wrap(m.scId),\n AssetId.wrap(m.assetId),\n m.assetAmount,\n D18.wrap(m.pricePoolPerAsset)\n );\n } else if (kind == MessageType.IssuedShares) {\n MessageLib.IssuedShares memory m = message.deserializeIssuedShares();\n investmentManager.issuedShares(\n PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.shareAmount, D18.wrap(m.pricePoolPerShare)\n );\n } else if (kind == MessageType.RevokedShares) {\n MessageLib.RevokedShares memory m = message.deserializeRevokedShares();\n investmentManager.revokedShares(\n PoolId.wrap(m.poolId),\n ShareClassId.wrap(m.scId),\n AssetId.wrap(m.assetId),\n m.assetAmount,\n m.shareAmount,\n D18.wrap(m.pricePoolPerShare)\n );\n } else if (kind == MessageType.TriggerSubmitQueuedShares) {\n MessageLib.TriggerSubmitQueuedShares memory m = message.deserializeTriggerSubmitQueuedShares();\n balanceSheet.submitQueuedShares(PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId));\n } else if (kind == MessageType.TriggerSubmitQueuedAssets) {\n MessageLib.TriggerSubmitQueuedAssets memory m = message.deserializeTriggerSubmitQueuedAssets();\n balanceSheet.submitQueuedAssets(PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), AssetId.wrap(m.assetId));\n } else if (kind == MessageType.SetQueue) {\n MessageLib.SetQueue memory m = message.deserializeSetQueue();\n balanceSheet.setQueue(PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.enabled);\n } else {\n revert InvalidMessage(uint8(kind));\n }\n }\n\n /// @inheritdoc IMessageProperties\n function isMessageRecovery(bytes calldata message) external pure returns (bool) {\n uint8 code = message.messageCode();\n return code == uint8(MessageType.InitiateRecovery) || code == uint8(MessageType.DisputeRecovery);\n }\n\n /// @inheritdoc IMessageProperties\n function messageLength(bytes calldata message) external pure returns (uint16) {\n return message.messageLength();\n }\n\n /// @inheritdoc IMessageProperties\n function messagePoolId(bytes calldata message) external pure returns (PoolId) {\n return message.messagePoolId();\n }\n}\n" + }, + "src/common/Root.sol": { + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {IAuth} from \"src/misc/interfaces/IAuth.sol\";\n\nimport {IRoot} from \"src/common/interfaces/IRoot.sol\";\n\n/// @title Root\n/// @notice Core contract that is a ward on all other deployed contracts.\n/// @dev Pausing can happen instantaneously, but relying on other contracts\n/// is restricted to the timelock set by the delay.\ncontract Root is Auth, IRoot {\n /// @dev To prevent filing a delay that would block any updates indefinitely\n uint256 internal constant MAX_DELAY = 4 weeks;\n\n bool public paused;\n uint256 public delay;\n mapping(address => uint256) public endorsements;\n mapping(address relyTarget => uint256 timestamp) public schedule;\n\n constructor(uint256 _delay, address deployer) Auth(deployer) {\n require(_delay <= MAX_DELAY, DelayTooLong());\n delay = _delay;\n }\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IRoot\n function file(bytes32 what, uint256 data) external auth {\n if (what == \"delay\") {\n require(data <= MAX_DELAY, DelayTooLong());\n delay = data;\n } else {\n revert FileUnrecognizedParam();\n }\n emit File(what, data);\n }\n\n /// @inheritdoc IRoot\n function endorse(address user) external auth {\n endorsements[user] = 1;\n emit Endorse(user);\n }\n\n /// @inheritdoc IRoot\n function veto(address user) external auth {\n endorsements[user] = 0;\n emit Veto(user);\n }\n\n /// @inheritdoc IRoot\n function endorsed(address user) external view returns (bool) {\n return endorsements[user] == 1;\n }\n\n //----------------------------------------------------------------------------------------------\n // Pause management\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IRoot\n function pause() external auth {\n paused = true;\n emit Pause();\n }\n\n /// @inheritdoc IRoot\n function unpause() external auth {\n paused = false;\n emit Unpause();\n }\n\n //----------------------------------------------------------------------------------------------\n // Timelocked ward management\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IRoot\n function scheduleRely(address target) external auth {\n schedule[target] = block.timestamp + delay;\n emit ScheduleRely(target, schedule[target]);\n }\n\n /// @inheritdoc IRoot\n function cancelRely(address target) external auth {\n require(schedule[target] != 0, TargetNotScheduled());\n schedule[target] = 0;\n emit CancelRely(target);\n }\n\n /// @inheritdoc IRoot\n function executeScheduledRely(address target) external {\n require(schedule[target] != 0, TargetNotScheduled());\n require(schedule[target] <= block.timestamp, TargetNotReady());\n\n wards[target] = 1;\n emit Rely(target);\n\n schedule[target] = 0;\n }\n\n //----------------------------------------------------------------------------------------------\n // External contract ward management\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IRoot\n function relyContract(address target, address user) external auth {\n IAuth(target).rely(user);\n emit RelyContract(target, user);\n }\n\n /// @inheritdoc IRoot\n function denyContract(address target, address user) external auth {\n IAuth(target).deny(user);\n emit DenyContract(target, user);\n }\n}\n" + }, + "src/common/TokenRecoverer.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {IRecoverable} from \"src/misc/interfaces/IRecoverable.sol\";\n\nimport {IRoot} from \"src/common/interfaces/IRoot.sol\";\nimport {ITokenRecoverer} from \"src/common/interfaces/ITokenRecoverer.sol\";\nimport {IRecoverable} from \"src/misc/interfaces/IRecoverable.sol\";\n\ncontract TokenRecoverer is Auth, ITokenRecoverer {\n IRoot public immutable root;\n\n constructor(IRoot root_, address deployer) Auth(deployer) {\n root = root_;\n }\n\n /// @notice inheritdoc ITokenRecoverer\n function recoverTokens(IRecoverable target, address token, uint256 tokenId, address to, uint256 amount)\n external\n auth\n {\n root.relyContract(address(target), address(this));\n\n if (tokenId == 0) {\n target.recoverTokens(token, to, amount);\n } else {\n target.recoverTokens(token, tokenId, to, amount);\n }\n\n root.denyContract(address(target), address(this));\n\n emit RecoverTokens(target, token, tokenId, to, amount);\n }\n}\n" + }, + "src/common/adapters/AxelarAdapter.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {\n IAxelarAdapter,\n IAdapter,\n IAxelarGateway,\n IAxelarGasService,\n AxelarSource,\n AxelarDestination,\n IAxelarExecutable\n} from \"src/common/interfaces/IAxelarAdapter.sol\";\nimport {IMessageHandler} from \"src/common/interfaces/IMessageHandler.sol\";\n\n/// @title Axelar Adapter\n/// @notice Routing contract that integrates with an Axelar Gateway\ncontract AxelarAdapter is Auth, IAxelarAdapter {\n using CastLib for *;\n\n IMessageHandler public immutable gateway;\n IAxelarGateway public immutable axelarGateway;\n IAxelarGasService public immutable axelarGasService;\n\n mapping(string axelarId => AxelarSource) public sources;\n mapping(uint16 centrifugeId => AxelarDestination) public destinations;\n\n constructor(IMessageHandler gateway_, address axelarGateway_, address axelarGasService_, address deployer)\n Auth(deployer)\n {\n gateway = gateway_;\n axelarGateway = IAxelarGateway(axelarGateway_);\n axelarGasService = IAxelarGasService(axelarGasService_);\n }\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IAxelarAdapter\n function file(bytes32 what, string calldata axelarId, uint16 centrifugeId, string calldata source) external auth {\n if (what == \"sources\") sources[axelarId] = AxelarSource(centrifugeId, keccak256(bytes(source)));\n else revert FileUnrecognizedParam();\n emit File(what, axelarId, centrifugeId, source);\n }\n\n /// @inheritdoc IAxelarAdapter\n function file(bytes32 what, uint16 centrifugeId, string calldata axelarId, string calldata destination)\n external\n auth\n {\n if (what == \"destinations\") destinations[centrifugeId] = AxelarDestination(axelarId, destination);\n else revert FileUnrecognizedParam();\n emit File(what, centrifugeId, axelarId, destination);\n }\n\n //----------------------------------------------------------------------------------------------\n // Incoming\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IAxelarExecutable\n function execute(\n bytes32 commandId,\n string calldata sourceAxelarId,\n string calldata sourceAddress,\n bytes calldata payload\n ) public {\n AxelarSource memory source = sources[sourceAxelarId];\n require(\n source.addressHash != bytes32(\"\") && source.addressHash == keccak256(bytes(sourceAddress)), InvalidAddress()\n );\n\n require(\n axelarGateway.validateContractCall(commandId, sourceAxelarId, sourceAddress, keccak256(payload)),\n NotApprovedByGateway()\n );\n\n gateway.handle(source.centrifugeId, payload);\n }\n\n //----------------------------------------------------------------------------------------------\n // Outgoing\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IAdapter\n function send(uint16 centrifugeId, bytes calldata payload, uint256, /* gasLimit */ address refund)\n external\n payable\n returns (bytes32 adapterData)\n {\n require(msg.sender == address(gateway), NotGateway());\n AxelarDestination memory destination = destinations[centrifugeId];\n require(bytes(destination.axelarId).length != 0, UnknownChainId());\n\n axelarGasService.payNativeGasForContractCall{value: msg.value}(\n address(this), destination.axelarId, destination.addr, payload, refund\n );\n\n axelarGateway.callContract(destination.axelarId, destination.addr, payload);\n\n adapterData = bytes32(\"\");\n }\n\n /// @inheritdoc IAdapter\n function estimate(uint16 centrifugeId, bytes calldata payload, uint256 gasLimit) public view returns (uint256) {\n AxelarDestination memory destination = destinations[centrifugeId];\n return axelarGasService.estimateGasFee(destination.axelarId, destination.addr, payload, gasLimit, bytes(\"\"));\n }\n}\n" + }, + "src/common/adapters/WormholeAdapter.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {IMessageHandler} from \"src/common/interfaces/IMessageHandler.sol\";\nimport {\n IWormholeAdapter,\n IAdapter,\n IWormholeRelayer,\n IWormholeDeliveryProvider,\n IWormholeReceiver,\n WormholeSource,\n WormholeDestination\n} from \"src/common/interfaces/IWormholeAdapter.sol\";\n\n/// @title Wormhole Adapter\n/// @notice Routing contract that integrates with the Wormhole Relayer service\ncontract WormholeAdapter is Auth, IWormholeAdapter {\n using CastLib for bytes32;\n\n uint16 public immutable localWormholeId;\n IMessageHandler public immutable gateway;\n IWormholeRelayer public immutable relayer;\n\n mapping(uint16 wormholeId => WormholeSource) public sources;\n mapping(uint16 centrifugeId => WormholeDestination) public destinations;\n\n constructor(IMessageHandler gateway_, address relayer_, address deployer) Auth(deployer) {\n gateway = gateway_;\n relayer = IWormholeRelayer(relayer_);\n\n IWormholeDeliveryProvider deliveryProvider = IWormholeDeliveryProvider(relayer.getDefaultDeliveryProvider());\n localWormholeId = deliveryProvider.chainId();\n }\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IWormholeAdapter\n function file(bytes32 what, uint16 centrifugeId, uint16 wormholeId, address addr) external auth {\n if (what == \"sources\") sources[wormholeId] = WormholeSource(centrifugeId, addr);\n else if (what == \"destinations\") destinations[centrifugeId] = WormholeDestination(wormholeId, addr);\n else revert FileUnrecognizedParam();\n emit File(what, centrifugeId, wormholeId, addr);\n }\n\n //----------------------------------------------------------------------------------------------\n // Incoming\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IWormholeReceiver\n function receiveWormholeMessages(\n bytes memory payload,\n bytes[] memory, /* additionalVaas */\n bytes32 sourceAddress,\n uint16 sourceWormholeId,\n bytes32 /* deliveryHash */\n ) external payable {\n WormholeSource memory source = sources[sourceWormholeId];\n require(source.addr != address(0) && source.addr == sourceAddress.toAddressLeftPadded(), InvalidSource());\n require(msg.sender == address(relayer), NotWormholeRelayer());\n\n gateway.handle(source.centrifugeId, payload);\n }\n\n //----------------------------------------------------------------------------------------------\n // Outgoing\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IAdapter\n function send(uint16 centrifugeId, bytes calldata payload, uint256 gasLimit, address refund)\n external\n payable\n returns (bytes32 adapterData)\n {\n require(msg.sender == address(gateway), NotGateway());\n WormholeDestination memory destination = destinations[centrifugeId];\n require(destination.wormholeId != 0, UnknownChainId());\n\n uint64 sequence = relayer.sendPayloadToEvm{value: msg.value}(\n destination.wormholeId, destination.addr, payload, 0, gasLimit, localWormholeId, refund\n );\n\n adapterData = bytes32(bytes8(sequence));\n }\n\n /// @inheritdoc IAdapter\n function estimate(uint16 centrifugeId, bytes calldata, uint256 gasLimit)\n public\n view\n returns (uint256 nativePriceQuote)\n {\n (nativePriceQuote,) = relayer.quoteEVMDeliveryPrice(destinations[centrifugeId].wormholeId, 0, gasLimit);\n }\n}\n" + }, + "src/common/interfaces/IAdapter.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IAuth} from \"src/misc/interfaces/IAuth.sol\";\n\ninterface IAdapter is IAuth {\n error NotGateway();\n error UnknownChainId();\n\n /// @notice Send a payload to the destination chain\n function send(uint16 centrifugeId, bytes calldata payload, uint256 gasLimit, address refund)\n external\n payable\n returns (bytes32 adapterData);\n\n /// @notice Estimate the total cost in native gas tokens\n function estimate(uint16 centrifugeId, bytes calldata payload, uint256 gasLimit) external view returns (uint256);\n}\n" + }, + "src/common/interfaces/IAxelarAdapter.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IAdapter} from \"src/common/interfaces/IAdapter.sol\";\n\n// From https://github.com/axelarnetwork/axelar-cgp-solidity/blob/main/contracts/interfaces/IAxelarGateway.sol\ninterface IAxelarGateway {\n function callContract(string calldata destinationChain, string calldata contractAddress, bytes calldata payload)\n external;\n\n function validateContractCall(\n bytes32 commandId,\n string calldata sourceChain,\n string calldata sourceAddress,\n bytes32 payloadHash\n ) external returns (bool);\n}\n\ninterface IAxelarGasService {\n // From\n // https://github.com/axelarnetwork/axelar-gmp-sdk-solidity/blob/00682b6c3db0cc922ec0c4ea3791852c93d7ae31/contracts/gas-estimation/InterchainGasEstimation.sol#L48\n function estimateGasFee(\n string calldata destinationChain,\n string calldata destinationAddress,\n bytes calldata payload,\n uint256 executionGasLimit,\n bytes calldata params\n ) external view returns (uint256 gasEstimate);\n\n // From https://github.com/axelarnetwork/axelar-cgp-solidity/blob/main/contracts/interfaces/IAxelarGasService.sol\n function payNativeGasForContractCall(\n address sender,\n string calldata destinationChain,\n string calldata destinationAddress,\n bytes calldata payload,\n address refundAddress\n ) external payable;\n}\n\n// From\n// https://github.com/axelarnetwork/axelar-gmp-sdk-solidity/blob/00682b6c3db0cc922ec0c4ea3791852c93d7ae31/contracts/interfaces/IAxelarExecutable.sol#L14\ninterface IAxelarExecutable {\n /**\n * @dev Thrown when a function is called with an invalid address.\n */\n error InvalidAddress();\n\n /**\n * @dev Thrown when the call is not approved by the Axelar Gateway.\n */\n error NotApprovedByGateway();\n\n /**\n * @notice Executes the specified command sent from another chain.\n * @dev This function is called by the Axelar Gateway to carry out cross-chain commands.\n * Reverts if the call is not approved by the gateway or other checks fail.\n * @param commandId The identifier of the command to execute.\n * @param sourceChain The name of the source chain from where the command originated.\n * @param sourceAddress The address on the source chain that sent the command.\n * @param payload The payload of the command to be executed. This typically includes the function selector and\n * encoded arguments.\n */\n function execute(\n bytes32 commandId,\n string calldata sourceChain,\n string calldata sourceAddress,\n bytes calldata payload\n ) external;\n}\n\nstruct AxelarSource {\n uint16 centrifugeId;\n bytes32 addressHash;\n}\n\nstruct AxelarDestination {\n string axelarId;\n string addr;\n}\n\ninterface IAxelarAdapter is IAdapter, IAxelarExecutable {\n event File(bytes32 indexed what, string axelarId, uint16 centrifugeId, string source);\n event File(bytes32 indexed what, uint16 centrifugeId, string axelarId, string destination);\n\n error FileUnrecognizedParam();\n\n function file(bytes32 what, string calldata axelarId, uint16 centrifugeId, string calldata source) external;\n function file(bytes32 what, uint16 centrifugeId, string calldata axelarId, string calldata destination) external;\n}\n" + }, + "src/common/interfaces/IGasService.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\ninterface IGasService {\n /// @notice Gas limit for the execution cost of an individual message in a remote chain.\n /// @dev NOTE: In the future we could want to dispatch:\n /// - by destination chain (for non-EVM chains)\n /// - by message type\n /// - by inspecting the payload checking different subsmessages that alter the endpoint processing\n /// @param centrifugeId Where to the cost is defined\n /// @param message Individual message\n /// @return Estimated cost in WEI units\n function gasLimit(uint16 centrifugeId, bytes calldata message) external view returns (uint128);\n\n /// @notice Gas limit for the execution cost of a batch in a remote chain.\n /// @param centrifugeId Where to the cost is defined\n /// @return Max cost in WEI units\n function maxBatchSize(uint16 centrifugeId) external view returns (uint128);\n}\n" + }, + "src/common/interfaces/IGateway.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IRecoverable} from \"src/misc/interfaces/IRecoverable.sol\";\n\nimport {IGatewayHandler} from \"src/common/interfaces/IGatewayHandlers.sol\";\nimport {IMessageHandler} from \"src/common/interfaces/IMessageHandler.sol\";\nimport {IMessageSender} from \"src/common/interfaces/IMessageSender.sol\";\nimport {IAdapter} from \"src/common/interfaces/IAdapter.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\n\nuint8 constant MAX_ADAPTER_COUNT = 8;\n\n/// @notice Interface for dispatch-only gateway\ninterface IGateway is IMessageHandler, IMessageSender, IGatewayHandler {\n /// @dev Each adapter struct is packed with the quorum to reduce SLOADs on handle\n struct Adapter {\n /// @notice Starts at 1 and maps to id - 1 as the index on the adapters array\n uint8 id;\n /// @notice Number of votes required for a message to be executed\n uint8 quorum;\n /// @notice Each time the quorum is decreased, a new session starts which invalidates old votes\n uint64 activeSessionId;\n }\n\n struct InboundBatch {\n /// @dev Counts are stored as integers (instead of boolean values) to accommodate duplicate\n /// messages (e.g. two investments from the same user with the same amount) being\n /// processed in parallel. The entire struct is packed in a single bytes32 slot.\n /// Max uint16 = 65,535 so at most 65,535 duplicate messages can be processed in parallel.\n uint16[MAX_ADAPTER_COUNT] votes;\n /// @notice Each time adapters are updated, a new session starts which invalidates old votes\n uint64 sessionId;\n bytes pendingBatch;\n }\n\n struct Funds {\n /// @notice Funds associated to pay for sending messages\n /// @dev Overflows with type(uint64).max / 10**18 = 7.923 × 10^10 ETH\n uint96 value;\n /// @notice Address where to refund the remaining gas\n IRecoverable refund;\n }\n\n // Used to bypass stack too deep issue\n struct SendData {\n bytes32 batchHash;\n bytes32 payloadId;\n uint256[] gasCost;\n }\n\n struct Underpaid {\n uint128 counter;\n uint128 gasLimit;\n }\n\n // --- Events ---\n event PrepareMessage(uint16 indexed centrifugeId, PoolId poolId, bytes message);\n event UnderpaidBatch(uint16 indexed centrifugeId, bytes batch);\n event RepayBatch(uint16 indexed centrifugeId, bytes batch);\n event SendBatch(\n uint16 indexed centrifugeId,\n bytes32 indexed payloadId,\n bytes batch,\n IAdapter adapter,\n bytes32 adapterData,\n address refund\n );\n event SendProof(\n uint16 indexed centrifugeId, bytes32 indexed payloadId, bytes32 batchHash, IAdapter adapter, bytes32 adapterData\n );\n event HandleBatch(uint16 indexed centrifugeId, bytes32 indexed payloadId, bytes batch, IAdapter adapter);\n event HandleProof(uint16 indexed centrifugeId, bytes32 indexed payloadId, bytes32 batchHash, IAdapter adapter);\n event ExecuteMessage(uint16 indexed centrifugeId, bytes message);\n event FailMessage(uint16 indexed centrifugeId, bytes message, bytes error);\n\n event RecoverMessage(IAdapter adapter, bytes message);\n event RecoverProof(IAdapter adapter, bytes32 batchHash);\n event InitiateRecovery(uint16 centrifugeId, bytes32 batchHash, IAdapter adapter);\n event DisputeRecovery(uint16 centrifugeId, bytes32 batchHash, IAdapter adapter);\n event ExecuteRecovery(uint16 centrifugeId, bytes message, IAdapter adapter);\n\n event File(bytes32 indexed what, uint16 centrifugeId, IAdapter[] adapters);\n event File(bytes32 indexed what, address addr);\n\n event SetRefundAddress(PoolId poolId, IRecoverable refund);\n event SubsidizePool(PoolId indexed poolId, address indexed sender, uint256 amount);\n\n /// @notice Dispatched when the `what` parameter of `file()` is not supported by the implementation.\n error FileUnrecognizedParam();\n\n /// @notice Dispatched when the batch is ended without starting it.\n error NoBatched();\n\n /// @notice Dispatched when the gateway is paused.\n error Paused();\n\n /// @notice Dispatched when the gateway is configured with a number of adapter exceeding the maximum.\n error ExceedsMax();\n\n /// @notice Dispatched when the gateway is configured with an empty adapter set.\n error EmptyAdapterSet();\n\n /// @notice Dispatched when the gateway is configured with duplicate adapters.\n error NoDuplicatesAllowed();\n\n /// @notice Dispatched when the gateway tries to handle a message from an adaptet not contained in the adapter set.\n error InvalidAdapter();\n\n /// @notice Dispatched when the gateway tries to recover a recovery message, which is not allowed.\n error RecoveryPayloadRecovered();\n\n /// @notice Dispatched when the gateway tries to handle a proof from a non proof adapter.\n error NonProofAdapter();\n\n /// @notice Dispatched when the gateway tries to handle a batch from a non message adapter.\n error NonBatchAdapter();\n\n /// @notice Dispatched when a recovery message is executed without being initiated.\n error RecoveryNotInitiated();\n\n /// @notice Dispatched when a recovery message is executed without waiting the challenge period.\n error RecoveryChallengePeriodNotEnded();\n\n /// @notice Dispatched when a the gateway tries to send an empty message.\n error EmptyMessage();\n\n /// @notice Dispatched when a the gateway has not enough fuel to send a message.\n /// Only dispatched in PayTransaction method\n error NotEnoughTransactionGas();\n\n /// @notice Dispatched when a message that has not failed is retried.\n error NotFailedMessage();\n\n /// @notice Dispatched when a batch that has not been underpaid is repaid.\n error NotUnderpaidBatch();\n\n /// @notice Dispatched when a batch is repaid with insufficient funds.\n error InsufficientFundsForRepayment();\n\n /// @notice Dispatched when a message is added to a batch that causes it to exceed the max batch size.\n error ExceedsMaxBatchSize();\n\n /// @notice Dispatched when a refund address is not set.\n error RefundAddressNotSet();\n\n // --- Administration ---\n /// @notice Used to update an array of addresses ( state variable ) on very rare occasions.\n /// @dev Currently it is used to update the supported adapters.\n /// @param what The name of the variable to be updated.\n /// @param centrifugeId Chain where the adapters are associated to.\n /// @param value New addresses.\n function file(bytes32 what, uint16 centrifugeId, IAdapter[] calldata value) external;\n\n /// @notice Used to update an address ( state variable ) on very rare occasions.\n /// @dev Currently used to update addresses of contract instances.\n /// @param what The name of the variable to be updated.\n /// @param data New address.\n function file(bytes32 what, address data) external;\n\n /// @notice Repay an underpaid batch. Send unused funds to subsidy pot of the pool.\n function repay(uint16 centrifugeId, bytes memory batch) external payable;\n\n /// @notice Retry a failed message.\n function retry(uint16 centrifugeId, bytes memory message) external;\n\n /// @notice Set the refund address for message associated to a poolId\n function setRefundAddress(PoolId poolId, IRecoverable refund) external;\n\n /// @notice Pay upfront to later be able to subsidize messages associated to a pool\n function subsidizePool(PoolId poolId) external payable;\n\n /// @notice Prepays for the TX cost for sending the messages through the adapters\n /// Currently being called from Vault Router only.\n /// In order to prepay, the method MUST be called with `msg.value`.\n /// Called is assumed to have called IGateway.estimate before calling this.\n function payTransaction(address payer) external payable;\n\n /// @notice Initialize batching message\n function startBatching() external;\n\n /// @notice Finalize batching messages and send the resulting batch message\n function endBatching() external;\n\n /// @notice Execute message recovery. After the challenge period, the recovery can be executed.\n /// If a malign adapter initiates message recovery,\n /// governance can dispute and immediately cancel the recovery, using any other valid adapter.\n ///\n /// Only 1 recovery can be outstanding per message hash. If multiple adapters fail at the same time,\n /// these will need to be recovered serially (increasing the challenge period for each failed adapter).\n /// @param centrifugeId Chain where the adapter is configured for\n /// @param adapter Adapter's address that the recovery is targeting\n /// @param message Hash of the message to be recovered\n function executeRecovery(uint16 centrifugeId, IAdapter adapter, bytes calldata message) external;\n\n // --- Helpers ---\n /// @notice A view method of the current quorum.abi\n /// @dev Quorum shows the amount of votes needed in order for a message to be dispatched further.\n /// The quorum is taken from the first adapter which is always the length of active adapters.\n /// @param centrifugeId Chain where the adapter is configured for\n /// return Needed amount\n function quorum(uint16 centrifugeId) external view returns (uint8);\n\n /// @notice Gets the current active routers session id.\n /// @dev When the adapters are updated with new ones,\n /// each new set of adapters has their own sessionId.\n /// Currently it uses sessionId of the previous set and\n /// increments it by 1. The idea of an activeSessionId is\n /// to invalidate any incoming messages from previously used adapters.\n /// @param centrifugeId Chain where the adapter is configured for\n function activeSessionId(uint16 centrifugeId) external view returns (uint64);\n\n /// @notice Counts how many times each incoming messages has been received per adapter.\n /// @dev It supports parallel messages ( duplicates ). That means that the incoming messages could be\n /// the result of two or more independ request from the user of the same type.\n /// i.e. Same user would like to deposit same underlying asset with the same amount more then once.\n /// @param centrifugeId Chain where the adapter is configured for\n /// @param batchHash The hash value of the incoming batch message.\n function votes(uint16 centrifugeId, bytes32 batchHash) external view returns (uint16[MAX_ADAPTER_COUNT] memory);\n\n /// @notice Used to calculate overall cost for bridging a payload on the first adapter and settling\n /// on the destination chain and bridging its payload proofs on n-1 adapter\n /// and settling on the destination chain.\n /// @param payload Used in gas cost calculations.\n /// @dev Currenly the payload is not taken into consideration.\n /// @return total Total cost for sending one message and corresponding proofs on through all adapters\n function estimate(uint16 centrifugeId, bytes calldata payload) external view returns (uint256 total);\n\n /// @notice Returns the address of the adapter at the given id.\n /// @param centrifugeId Chain where the adapter is configured for\n function adapters(uint16 centrifugeId, uint256 id) external view returns (IAdapter);\n\n /// @notice Returns the timestamp when the given recovery can be executed.\n /// @param centrifugeId Chain where the adapter is configured for\n function recoveries(uint16 centrifugeId, IAdapter adapter, bytes32 batchHash)\n external\n view\n returns (uint256 timestamp);\n\n /// @notice Returns the current gateway batching level.\n function isBatching() external view returns (bool);\n}\n" + }, + "src/common/interfaces/IGatewayHandlers.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {D18} from \"src/misc/types/D18.sol\";\n\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {IAdapter} from \"src/common/interfaces/IAdapter.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\n\n/// -----------------------------------------------------\n/// Common Handlers\n/// -----------------------------------------------------\n/// @notice Interface for Gateway methods called by messages\ninterface IGatewayHandler {\n /// @notice Initialize the recovery of a payload.\n /// @param centrifugeId Chain where the adapter is configured for\n /// @param adapter Adapter that the recovery was targeting\n /// @param payloadHash Hash of the payload being disputed\n function initiateRecovery(uint16 centrifugeId, IAdapter adapter, bytes32 payloadHash) external;\n\n /// @notice Cancel the recovery of a payload.\n /// @param centrifugeId Chain where the adapter is configured for\n /// @param adapter Adapter that the recovery was targeting\n /// @param payloadHash Hash of the payload being disputed\n function disputeRecovery(uint16 centrifugeId, IAdapter adapter, bytes32 payloadHash) external;\n}\n\n/// -----------------------------------------------------\n/// CP Handlers\n/// -----------------------------------------------------\n\n/// @notice Interface for CP methods called by messages\ninterface IHubGatewayHandler {\n /// @notice Tells that an asset was already registered in CV, in order to perform the corresponding register.\n function registerAsset(AssetId assetId, uint8 decimals) external;\n\n /// @notice Perform a deposit that was requested from CV.\n function depositRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId depositAssetId, uint128 amount)\n external;\n\n /// @notice Perform a redeem that was requested from CV.\n function redeemRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId payoutAssetId, uint128 amount)\n external;\n\n /// @notice Perform a deposit cancellation that was requested from CV.\n function cancelDepositRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId depositAssetId)\n external;\n\n /// @notice Perform a redeem cancellation that was requested from CV.\n function cancelRedeemRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId payoutAssetId) external;\n\n /// @notice Update a holding by request from CAL.\n function updateHoldingAmount(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n uint128 amount,\n D18 pricePoolPerAsset,\n bool isIncrease\n ) external;\n\n /// @notice Increases the total issuance of shares by request from CAL.\n function increaseShareIssuance(PoolId poolId, ShareClassId scId, uint128 amount) external;\n\n /// @notice Decreases the total issuance of shares by request from CAL.\n function decreaseShareIssuance(PoolId poolId, ShareClassId scId, uint128 amount) external;\n}\n\n/// -----------------------------------------------------\n/// CV Handlers\n/// -----------------------------------------------------\n\n/// @notice Interface for CV methods related to pools called by messages\ninterface IPoolManagerGatewayHandler {\n /// @notice New pool details from an existing Centrifuge pool are added.\n /// @dev The function can only be executed by the gateway contract.\n function addPool(PoolId poolId) external;\n\n /// @notice New share class details from an existing Centrifuge pool are added.\n /// @dev The function can only be executed by the gateway contract.\n function addShareClass(\n PoolId poolId,\n ShareClassId scId,\n string memory tokenName,\n string memory tokenSymbol,\n uint8 decimals,\n bytes32 salt,\n address hook\n ) external;\n\n /// @notice Updates the tokenName and tokenSymbol of a share class token\n /// @dev The function can only be executed by the gateway contract.\n function updateShareMetadata(PoolId poolId, ShareClassId scId, string memory tokenName, string memory tokenSymbol)\n external;\n\n /// @notice Updates the price of a share class token, i.e. the factor of pool currency amount per share class token\n /// @dev The function can only be executed by the gateway contract.\n /// @param poolId The pool id\n /// @param scId The share class id\n /// @param price The price of pool currency per share class token as factor.\n /// @param computedAt The timestamp when the price was computed\n function updatePricePoolPerShare(PoolId poolId, ShareClassId scId, uint128 price, uint64 computedAt) external;\n\n /// @notice Updates the price of an asset, i.e. the factor of pool currency amount per asset unit\n /// @dev The function can only be executed by the gateway contract.\n /// @param poolId The pool id\n /// @param scId The share class id\n /// @param assetId The asset id\n /// @param poolPerAsset The price of pool currency per asset unit as factor.\n /// @param computedAt The timestamp when the price was computed\n function updatePricePoolPerAsset(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n uint128 poolPerAsset,\n uint64 computedAt\n ) external;\n\n /// @notice Updates the hook of a share class token\n /// @param poolId The centrifuge pool id\n /// @param scId The share class id\n /// @param hook The new hook addres\n function updateShareHook(PoolId poolId, ShareClassId scId, address hook) external;\n\n /// @notice Updates the restrictions on a share class token for a specific user\n /// @param poolId The centrifuge pool id\n /// @param scId The share class id\n /// @param update The restriction update in the form of a bytes array indicating\n /// the restriction to be updated, the user to be updated, and a validUntil timestamp.\n function updateRestriction(PoolId poolId, ShareClassId scId, bytes memory update) external;\n\n /// @notice Mints share class tokens to a recipient\n /// @dev The function can only be executed internally or by the gateway contract.\n function handleTransferShares(PoolId poolId, ShareClassId scId, address destinationAddress, uint128 amount)\n external;\n\n /// @notice Updates the target address. Generic update function from CP to CV\n /// @param poolId The centrifuge pool id\n /// @param scId The share class id\n /// @param target The target address to be called\n /// @param update The payload to be processed by the target address\n function updateContract(PoolId poolId, ShareClassId scId, address target, bytes memory update) external;\n}\n\n/// @notice Interface for CV methods related to async investments called by messages\ninterface IRequestManagerGatewayHandler {\n /// @notice Signal from the Hub that an asynchronous investment order has been approved\n ///\n /// @dev This message needs to trigger making the asset amounts available to the pool-share-class.\n function approvedDeposits(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n uint128 assetAmount,\n D18 pricePoolPerAsset\n ) external;\n\n /// @notice Signal from the Hub that an asynchronous investment order has been finalized. Shares have been issued.\n ///\n /// @dev This message needs to trigger minting the new amount of shares.\n function issuedShares(PoolId poolId, ShareClassId scId, uint128 shareAmount, D18 pricePoolPerShare) external;\n\n /// @notice Signal from the Hub that an asynchronous redeem order has been finalized.\n ///\n /// @dev This messages needs to trigger reserving the asset amount for claims of redemptions by users.\n function revokedShares(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n uint128 assetAmount,\n uint128 shareAmount,\n D18 pricePoolPerShare\n ) external;\n\n // --- Deposits ---\n /// @notice Fulfills pending deposit requests after successful epoch execution on CP.\n /// The amount of shares that can be claimed by the user is minted and moved to the escrow contract.\n /// The MaxMint bookkeeping value is updated.\n /// The request fulfillment can be partial.\n /// @dev The shares in the escrow are reserved for the user and are transferred to the user on deposit\n /// and mint calls.\n function fulfillDepositRequest(\n PoolId poolId,\n ShareClassId scId,\n address user,\n AssetId assetId,\n uint128 assets,\n uint128 shares\n ) external;\n\n /// @notice Fulfills deposit request cancellation after successful epoch execution on CP.\n /// The amount of assets that can be claimed by the user is locked in the escrow contract.\n /// Updates claimableCancelDepositRequest bookkeeping value. The cancellation order execution can be\n /// partial.\n /// @dev The assets in the escrow are reserved for the user and are transferred to the user during\n /// claimCancelDepositRequest calls.\n /// `fulfillment` represents the decrease in `pendingDepositRequest`.\n /// This is a separate parameter from `assets` since there can be some precision loss when calculating this,\n /// which would lead to having dust in the pendingDepositRequest value and\n /// never closing out the request even after it is technically fulfilled.\n ///\n /// Example:\n /// User deposits 100 units of the vaults underlying asset.\n /// - At some point they make cancellation request. The order in which is not guaranteed\n /// Both requests arrive at CentrifugeChain. If the cancellation is first then all of the\n /// deposited amount will be cancelled.\n ///\n /// - There is the case where the deposit event is first and it gets completely fulfilled then\n /// No amount of the deposited asset will be cancelled.\n ///\n /// - There is the case where partially the deposit request is fulfilled. Let's say 40 units.\n /// Then the cancel request arrives.\n /// The remaining amount of deposited funds which is 60 units will cancelled.\n /// There is a scenario where the deposit funds might different from the pool currency so some\n /// swapping might happen. Either during this swapping or some fee collection or rounding there will be\n /// difference between the actual amount that will be returned to the user.\n /// `fulfillment` in this case will be 60 units but assets will be some lower amount because of the\n /// aforementioned reasons\n /// Let's assume the `asset` is 59. The user will be able to take back these 59 but\n /// in order to not let any dust, we use `fulfillment` in our calculations.\n ///\n /// `pendingDepositRequest` not necessary gets zeroed during this cancellation event.\n /// When CentrifugeChain process the cancel event on its side, part of the deposit might be fulfilled.\n /// In such case the chain will send two messages, one `fulfillDepositRequest` and one\n /// `fulfillCancelDepositRequest`. In the example above, given the 100 units\n /// deposited, 40 units are fulfilled and 60 can be cancelled.\n /// The two messages sent from CentrifugeChain are not guaranteed to arrive in order.\n ///\n /// Assuming first is the `fulfillCancelDepositRequest` the `pendingDepositRequest` here will be reduced to\n /// 60 units only. Then the `fulfillCancelDepositRequest` arrives with `fulfillment` 60. This amount is\n /// removed from `pendingDepositRequests`. Since there are not more pendingDepositRequest` the\n /// `pendingCancelDepositRequest` gets deleted.\n ///\n /// Assuming first the `fulfillCancelDepositRequest` arrives then the `pendingDepositRequest` will be 100.\n /// `fulfillment` is 60 so we are left with `pendingDepositRequest` equals to 40 ( 100 - 60 ).\n /// Then the second message arrives which is `fulfillDepositRequest`. ( Check `fulfillDepositRequest`\n /// implementation for details.)\n /// When it arrives the `pendingDepositRequest` is 40 and the assets is 40\n /// so there are no more `pendingDepositRequest` and right there the `pendingCancelDepositRequest will be\n /// deleted.\n function fulfillCancelDepositRequest(\n PoolId poolId,\n ShareClassId scId,\n address user,\n AssetId assetId,\n uint128 assets,\n uint128 fulfillment\n ) external;\n\n // --- Redeems ---\n /// @notice Fulfills pending redeem requests after successful epoch execution on CP.\n /// The amount of redeemed shares is burned. The amount of assets that can be claimed by the user in\n /// return is locked in the escrow contract. The MaxWithdraw bookkeeping value is updated.\n /// The request fulfillment can be partial.\n /// @dev The assets in the escrow are reserved for the user and are transferred to the user on redeem\n /// and withdraw calls.\n function fulfillRedeemRequest(\n PoolId poolId,\n ShareClassId scId,\n address user,\n AssetId assetId,\n uint128 assets,\n uint128 shares\n ) external;\n\n /// @notice Fulfills redeem request cancellation after successful epoch execution on CP.\n /// The amount of shares that can be claimed by the user is locked in the escrow contract.\n /// Updates claimableCancelRedeemRequest bookkeeping value. The cancellation order execution can also be\n /// partial.\n /// @dev The shares in the escrow are reserved for the user and are transferred to the user during\n /// claimCancelRedeemRequest calls.\n function fulfillCancelRedeemRequest(PoolId poolId, ShareClassId scId, address user, AssetId assetId, uint128 shares)\n external;\n}\n\n/// @notice Interface for CV methods related to epoch called by messages\ninterface IBalanceSheetGatewayHandler {\n function triggerDeposit(PoolId poolId, ShareClassId scId, AssetId assetId, address provider, uint128 amount)\n external;\n\n function triggerWithdraw(PoolId poolId, ShareClassId scId, AssetId assetId, address receiver, uint128 amount)\n external;\n\n function triggerIssueShares(PoolId poolId, ShareClassId scId, address to, uint128 shares) external;\n\n function submitQueuedShares(PoolId poolId, ShareClassId scId) external;\n\n function submitQueuedAssets(PoolId poolId, ShareClassId scId, AssetId assetId) external;\n\n function setQueue(PoolId poolId, ShareClassId scId, bool enabled) external;\n}\n" + }, + "src/common/interfaces/IGatewaySenders.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {D18} from \"src/misc/types/D18.sol\";\n\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\n\ninterface ILocalCentrifugeId {\n function localCentrifugeId() external view returns (uint16);\n}\n\n/// @notice Interface for dispatch-only gateway\ninterface IRootMessageSender {\n /// @notice Creates and send the message\n function sendScheduleUpgrade(uint16 centrifugeId, bytes32 target) external;\n\n /// @notice Creates and send the message\n function sendCancelUpgrade(uint16 centrifugeId, bytes32 target) external;\n\n /// @notice Creates and send the message\n function sendRecoverTokens(\n uint16 centrifugeId,\n bytes32 target,\n bytes32 token,\n uint256 tokenId,\n bytes32 to,\n uint256 amount\n ) external;\n\n /// @notice Creates and send the message\n function sendInitiateRecovery(uint16 centrifugeId, uint16 adapterCentrifugeId, bytes32 adapter, bytes32 hash)\n external;\n\n /// @notice Creates and send the message\n function sendDisputeRecovery(uint16 centrifugeId, uint16 adapterCentrifugeId, bytes32 adapter, bytes32 hash)\n external;\n}\n\n/// @notice Interface for dispatch-only gateway\ninterface IPoolMessageSender is ILocalCentrifugeId {\n /// @notice Creates and send the message\n function sendNotifyPool(uint16 centrifugeId, PoolId poolId) external;\n\n /// @notice Creates and send the message\n function sendNotifyShareClass(\n uint16 centrifugeId,\n PoolId poolId,\n ShareClassId scId,\n string memory name,\n string memory symbol,\n uint8 decimals,\n bytes32 salt,\n bytes32 hook\n ) external;\n\n /// @notice Creates and send the message\n function sendNotifyShareMetadata(\n uint16 centrifugeId,\n PoolId poolId,\n ShareClassId scId,\n string memory name,\n string memory symbol\n ) external;\n\n /// @notice Creates and send the message\n function sendUpdateShareHook(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bytes32 hook) external;\n\n /// @notice Creates and send the message\n function sendNotifyPricePoolPerShare(uint16 chainId, PoolId poolId, ShareClassId scId, D18 pricePerShare)\n external;\n\n /// @notice Creates and send the message\n function sendNotifyPricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId, D18 pricePerShare)\n external;\n\n /// @notice Creates and send the message\n function sendFulfilledDepositRequest(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n bytes32 investor,\n uint128 assetAmount,\n uint128 shareAmount\n ) external;\n\n /// @notice Creates and send the message\n function sendFulfilledRedeemRequest(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n bytes32 investor,\n uint128 assetAmount,\n uint128 shareAmount\n ) external;\n\n /// @notice Creates and send the message\n function sendFulfilledCancelDepositRequest(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n bytes32 investor,\n uint128 cancelledAmount\n ) external;\n\n /// @notice Creates and send the message\n function sendFulfilledCancelRedeemRequest(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n bytes32 investor,\n uint128 cancelledShares\n ) external;\n\n /// @notice Creates and send the message\n function sendUpdateRestriction(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bytes calldata payload)\n external;\n\n /// @notice Creates and send the message\n function sendUpdateContract(\n uint16 centrifugeId,\n PoolId poolId,\n ShareClassId scId,\n bytes32 target,\n bytes calldata payload\n ) external;\n\n /// @notice Creates and send the message\n function sendApprovedDeposits(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n uint128 assetAmount,\n D18 pricePoolPerAsset\n ) external;\n\n // @notice Creates and send the message\n function sendIssuedShares(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n uint128 shareAmount,\n D18 pricePoolPerShare\n ) external;\n\n /// @notice Creates and send the message\n function sendRevokedShares(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n uint128 assetAmount,\n uint128 shareAmount,\n D18 pricePoolPerShare\n ) external;\n\n /// @notice Creates and send the message\n function sendTriggerIssueShares(uint16 centrifugeId, PoolId poolId, ShareClassId scId, address who, uint128 shares)\n external;\n\n /// @notice Creates and send the message\n function sendTriggerSubmitQueuedShares(uint16 centrifugeId, PoolId poolId, ShareClassId scId) external;\n\n /// @notice Creates and send the message\n function sendTriggerSubmitQueuedAssets(PoolId poolId, ShareClassId scId, AssetId assetId) external;\n\n /// @notice Creates and send the message\n function sendSetQueue(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bool enabled) external;\n}\n\n/// @notice Interface for dispatch-only gateway\ninterface IVaultMessageSender is ILocalCentrifugeId {\n /// @notice Creates and send the message\n function sendTransferShares(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bytes32 receiver, uint128 amount)\n external;\n\n /// @notice Creates and send the message\n function sendDepositRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId assetId, uint128 amount)\n external;\n\n /// @notice Creates and send the message\n function sendRedeemRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId assetId, uint128 amount)\n external;\n\n /// @notice Creates and send the message\n function sendCancelDepositRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId assetId) external;\n\n /// @notice Creates and send the message\n function sendCancelRedeemRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId assetId) external;\n\n /// @notice Creates and send the message\n function sendRegisterAsset(uint16 centrifugeId, AssetId assetId, uint8 decimals) external;\n\n /// @notice Creates and send the message\n function sendUpdateHoldingAmount(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n address provider,\n uint128 amount,\n D18 pricePoolPerAsset,\n bool isIncrease\n ) external;\n\n /// @notice Creates and send the message\n function sendUpdateShares(PoolId poolId, ShareClassId scId, uint128 shares, bool isIssuance) external;\n}\n" + }, + "src/common/interfaces/IGuardian.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {IAdapter} from \"src/common/interfaces/IAdapter.sol\";\n\ninterface ISafe {\n function isOwner(address signer) external view returns (bool);\n}\n\ninterface IGuardian {\n error NotTheAuthorizedSafe();\n error NotTheAuthorizedSafeOrItsOwner();\n\n /// @notice Dispatched when the `what` parameter of `file()` is not supported by the implementation.\n error FileUnrecognizedParam();\n\n /// @notice Emitted when a call to `file()` was performed.\n event File(bytes32 indexed what, address addr);\n\n /// @notice Return the linked Safe\n function safe() external view returns (ISafe);\n\n /// @notice Updates a contract parameter.\n /// @param what Name of the parameter to update.\n /// Accepts a `bytes32` representation of 'sender' string value.\n /// @param data New value given to the `what` parameter\n function file(bytes32 what, address data) external;\n\n /// @notice Registers a new pool\n function createPool(PoolId poolId, address admin, AssetId currency) external;\n\n /// @notice Pause the protocol\n /// @dev callable by both safe and owners\n function pause() external;\n\n /// @notice Unpause the protocol\n /// @dev callable by safe only\n function unpause() external;\n\n /// @notice Schedule relying a target address on Root\n /// @dev callable by safe only\n function scheduleRely(address target) external;\n\n /// @notice Cancel a scheduled rely\n /// @dev callable by safe only\n function cancelRely(address target) external;\n\n /// @notice Schedule an upgrade (scheduled rely) on a specific chain\n /// @dev Only supports EVM targets today\n function scheduleUpgrade(uint16 centrifugeId, address target) external;\n\n /// @notice Cancel an upgrade (scheduled rely) on a specific chain\n /// @dev Only supports EVM targets today\n function cancelUpgrade(uint16 centrifugeId, address target) external;\n\n /// @notice Recover tokens on a specific chain\n /// @dev Only supports EVM targets today\n function recoverTokens(\n uint16 centrifugeId,\n address target,\n address token,\n uint256 tokenId,\n address to,\n uint256 amount\n ) external;\n\n /// @notice Initiate a gateway payload recovery on a specific chain\n /// @dev Only supports EVM targets today\n function initiateRecovery(uint16 centrifugeId, uint16 adapterCentrifugeId, IAdapter adapter, bytes32 hash)\n external;\n\n /// @notice Dispute a gateway paylaod recovery on a specific chain\n /// @dev Only supports EVM targets today\n function disputeRecovery(uint16 centrifugeId, uint16 adapterCentrifugeId, IAdapter adapter, bytes32 hash)\n external;\n}\n" + }, + "src/common/interfaces/IGuardianActions.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\n\ninterface IHubGuardianActions {\n /// @notice Creates a new pool. `msg.sender` will be the admin of the created pool.\n /// @param currency The pool currency. Usually an AssetId identifying by a ISO4217 code.\n function createPool(PoolId poolId, address admin, AssetId currency) external payable;\n}\n" + }, + "src/common/interfaces/IHook.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IERC165} from \"src/misc/interfaces/IERC7575.sol\";\n\nstruct HookData {\n bytes16 from;\n bytes16 to;\n}\n\nuint8 constant SUCCESS_CODE_ID = 0;\nstring constant SUCCESS_MESSAGE = \"transfer-allowed\";\n\nuint8 constant ERROR_CODE_ID = 1;\nstring constant ERROR_MESSAGE = \"transfer-blocked\";\n\n/// @dev Magic address denoting a transfer to the escrow\n/// @dev Solely used for gas saving since escrow is per pool\naddress constant ESCROW_HOOK_ID = address(uint160(uint8(0xce)));\n\n/// @notice Hook interface to customize share token behaviour\n/// @dev To detect specific system actions:\n/// Deposit request: address(0) -> address(user)\n/// Deposit claim: ESCROW_HOOK_ID -> address(user)\n/// Redeem request: address(user) -> ESCROW_HOOK_ID\n/// Redeem claim: address(user) -> address(0)\n/// Cross-chain transfer: address(user) -> address(uint160(chainId))\ninterface IHook is IERC165 {\n // --- Errors ---\n error TransferBlocked();\n error InvalidUpdate();\n\n /// @notice Callback on standard ERC20 transfer.\n /// @dev MUST return bytes4(keccak256(\"onERC20Transfer(address,address,uint256,(bytes16,bytes16))\"))\n /// if successful\n function onERC20Transfer(address from, address to, uint256 value, HookData calldata hookdata)\n external\n returns (bytes4);\n\n /// @notice Callback on authorized ERC20 transfer.\n /// @dev Cannot be blocked, can only be used to update state.\n /// Return value is ignored, only kept for compatibility with V2 share tokens.\n function onERC20AuthTransfer(address sender, address from, address to, uint256 value, HookData calldata hookdata)\n external\n returns (bytes4);\n\n /// @notice Check if given transfer can be performed\n function checkERC20Transfer(address from, address to, uint256 value, HookData calldata hookData)\n external\n view\n returns (bool);\n\n /// @notice Update a set of restriction for a token\n /// @dev MAY be user specific, which would be included in the encoded `update` value\n function updateRestriction(address token, bytes memory update) external;\n}\n" + }, + "src/common/interfaces/IMessageDispatcher.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IVaultMessageSender, IPoolMessageSender, IRootMessageSender} from \"src/common/interfaces/IGatewaySenders.sol\";\n\ninterface IMessageDispatcher is IRootMessageSender, IVaultMessageSender, IPoolMessageSender {\n /// @notice Emitted when a call to `file()` was performed.\n event File(bytes32 indexed what, address addr);\n\n /// @notice Dispatched when the `what` parameter of `file()` is not supported by the implementation.\n error FileUnrecognizedParam();\n\n /// @notice Updates a contract parameter.\n /// @param what Name of the parameter to update.\n /// Accepts a `bytes32` representation of 'hubRegistry' string value.\n /// @param data New value given to the `what` parameter\n function file(bytes32 what, address data) external;\n\n /// @notice Estimate sending a message through the gateway.\n /// If the message is to the same centrifugeId, then the estimation is 0.\n function estimate(uint16 centrifugeId, bytes calldata payload) external view returns (uint256 amount);\n}\n" + }, + "src/common/interfaces/IMessageHandler.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\n/// @notice Generic interface for entities that handle incoming messages\ninterface IMessageHandler {\n /// @notice Dispatched when an invalid message is trying to handle\n error InvalidMessage(uint8 code);\n\n /// @notice Handling incoming messages.\n /// @param centrifugeId Source chain\n /// @param message Incoming message\n function handle(uint16 centrifugeId, bytes calldata message) external;\n}\n" + }, + "src/common/interfaces/IMessageProcessor.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IMessageHandler} from \"src/common/interfaces/IMessageHandler.sol\";\nimport {IMessageProperties} from \"src/common/interfaces/IMessageProperties.sol\";\n\ninterface IMessageProcessor is IMessageHandler, IMessageProperties {\n /// @notice Emitted when a call to `file()` was performed.\n event File(bytes32 indexed what, address addr);\n\n /// @notice Dispatched when the `what` parameter of `file()` is not supported by the implementation.\n error FileUnrecognizedParam();\n\n /// @notice Updates a contract parameter.\n /// @param what Name of the parameter to update.\n /// Accepts a `bytes32` representation of 'hubRegistry' string value.\n /// @param data New value given to the `what` parameter\n function file(bytes32 what, address data) external;\n}\n" + }, + "src/common/interfaces/IMessageProperties.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\n\n/// @notice Defines methods to get properties from raw messages\ninterface IMessageProperties {\n /// @notice Inspect the message to tell if the message is recovery message\n function isMessageRecovery(bytes calldata message) external pure returns (bool);\n\n /// @notice Inspect the message to return the length\n function messageLength(bytes calldata message) external pure returns (uint16);\n\n /// @notice Inspect the message to return the associated PoolId if any\n function messagePoolId(bytes calldata message) external pure returns (PoolId);\n}\n" + }, + "src/common/interfaces/IMessageSender.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\n/// @notice Generic interface for entities that handles outgoing messages\ninterface IMessageSender {\n /// @notice Handling outgoing messages.\n /// @param centrifugeId Destination chain\n function send(uint16 centrifugeId, bytes calldata message) external;\n}\n" + }, + "src/common/interfaces/IRoot.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IMessageHandler} from \"src/common/interfaces/IMessageHandler.sol\";\n\ninterface IRoot {\n // --- Events ---\n event File(bytes32 indexed what, uint256 data);\n event Pause();\n event Unpause();\n event ScheduleRely(address indexed target, uint256 indexed scheduledTime);\n event CancelRely(address indexed target);\n event RelyContract(address indexed target, address indexed user);\n event DenyContract(address indexed target, address indexed user);\n event Endorse(address indexed user);\n event Veto(address indexed user);\n\n error DelayTooLong();\n error FileUnrecognizedParam();\n error TargetNotScheduled();\n error TargetNotReady();\n\n /// @notice Returns whether the root is paused\n function paused() external view returns (bool);\n\n /// @notice Returns the current timelock for adding new wards\n function delay() external view returns (uint256);\n\n /// @notice Trusted contracts within the system\n function endorsements(address target) external view returns (uint256);\n\n /// @notice Returns when `relyTarget` has passed the timelock\n function schedule(address relyTarget) external view returns (uint256 timestamp);\n\n // --- Administration ---\n /// @notice Updates a contract parameter\n /// @param what Accepts a bytes32 representation of 'delay'\n function file(bytes32 what, uint256 data) external;\n\n /// --- Endorsements ---\n /// @notice Endorses the `user`\n /// @dev Endorsed users are trusted contracts in the system. They are allowed to bypass\n /// token restrictions (e.g. the Escrow can automatically receive share class tokens by being endorsed), and\n /// can automatically set operators in ERC-7540 vaults (e.g. the VaultRouter) is always an operator.\n function endorse(address user) external;\n\n /// @notice Removes the endorsed user\n function veto(address user) external;\n\n /// @notice Returns whether the user is endorsed\n function endorsed(address user) external view returns (bool);\n\n // --- Pause management ---\n /// @notice Pause any contracts that depend on `Root.paused()`\n function pause() external;\n\n /// @notice Unpause any contracts that depend on `Root.paused()`\n function unpause() external;\n\n /// --- Timelocked ward management ---\n /// @notice Schedule relying a new ward after the delay has passed\n function scheduleRely(address target) external;\n\n /// @notice Cancel a pending scheduled rely\n function cancelRely(address target) external;\n\n /// @notice Execute a scheduled rely\n /// @dev Can be triggered by anyone since the scheduling is protected\n function executeScheduledRely(address target) external;\n\n /// --- External contract ward management ---\n /// @notice Make an address a ward on any contract that Root is a ward on\n function relyContract(address target, address user) external;\n\n /// @notice Removes an address as a ward on any contract that Root is a ward on\n function denyContract(address target, address user) external;\n}\n" + }, + "src/common/interfaces/ITokenRecoverer.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IRecoverable} from \"src/misc/interfaces/IRecoverable.sol\";\n\ninterface ITokenRecoverer {\n event RecoverTokens(\n IRecoverable indexed target, address indexed token, uint256 tokenId, address indexed to, uint256 amount\n );\n\n function recoverTokens(IRecoverable target, address token, uint256 tokenId, address to, uint256 amount) external;\n}\n" + }, + "src/common/interfaces/IWormholeAdapter.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IAdapter} from \"src/common/interfaces/IAdapter.sol\";\n\n// From https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/interfaces/IWormholeRelayer.sol#L75\ninterface IWormholeRelayer {\n /**\n * @notice Publishes an instruction for the default delivery provider\n * to relay a payload to the address `targetAddress` on chain `targetChain`\n * with gas limit `gasLimit` and `msg.value` equal to `receiverValue`\n *\n * Any refunds (from leftover gas) will be sent to `refundAddress` on chain `refundChain`\n * `targetAddress` must implement the IWormholeReceiver interface\n *\n * This function must be called with `msg.value` equal to `quoteEVMDeliveryPrice(targetChain, receiverValue,\n * gasLimit)`\n *\n * @param targetChain in Wormhole Chain ID format\n * @param targetAddress address to call on targetChain (that implements IWormholeReceiver)\n * @param payload arbitrary bytes to pass in as parameter in call to `targetAddress`\n * @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain\n * currency units)\n * @param gasLimit gas limit with which to call `targetAddress`. Any units of gas unused will be refunded according\n * to the\n * `targetChainRefundPerGasUnused` rate quoted by the delivery provider\n * @param refundChain The chain to deliver any refund to, in Wormhole Chain ID format\n * @param refundAddress The address on `refundChain` to deliver any refund to\n * @return sequence sequence number of published VAA containing delivery instructions\n */\n function sendPayloadToEvm(\n uint16 targetChain,\n address targetAddress,\n bytes memory payload,\n uint256 receiverValue,\n uint256 gasLimit,\n uint16 refundChain,\n address refundAddress\n ) external payable returns (uint64 sequence);\n\n /**\n * @notice Returns the price to request a relay to chain `targetChain`, using the default delivery provider\n *\n * @param targetChain in Wormhole Chain ID format\n * @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain\n * currency units)\n * @param gasLimit gas limit with which to call `targetAddress`.\n * @return nativePriceQuote Price, in units of current chain currency, that the delivery provider charges to perform\n * the relay\n * @return targetChainRefundPerGasUnused amount of target chain currency that will be refunded per unit of gas\n * unused,\n * if a refundAddress is specified.\n * Note: This value can be overridden by the delivery provider on the target chain. The returned value here\n * should be considered to be a\n * promise by the delivery provider of the amount of refund per gas unused that will be returned to the\n * refundAddress at the target chain.\n * If a delivery provider decides to override, this will be visible as part of the emitted Delivery event on\n * the target chain.\n */\n function quoteEVMDeliveryPrice(uint16 targetChain, uint256 receiverValue, uint256 gasLimit)\n external\n view\n returns (uint256 nativePriceQuote, uint256 targetChainRefundPerGasUnused);\n\n /**\n * @notice Returns the address of the current default delivery provider\n * @return deliveryProvider The address of (the default delivery provider)'s contract on this source\n * chain. This must be a contract that implements IDeliveryProvider.\n */\n function getDefaultDeliveryProvider() external view returns (address deliveryProvider);\n}\n\ninterface IWormholeDeliveryProvider {\n /// @notice Returns the chain ID.\n function chainId() external view returns (uint16);\n}\n\n// From\n// https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IWormholeReceiver.sol\ninterface IWormholeReceiver {\n /**\n * @notice When a `send` is performed with this contract as the target, this function will be\n * invoked by the WormholeRelayer contract\n *\n * NOTE: This function should be restricted such that only the Wormhole Relayer contract can call it.\n *\n * We also recommend that this function checks that `sourceChain` and `sourceAddress` are indeed who\n * you expect to have requested the calling of `send` on the source chain\n *\n * The invocation of this function corresponding to the `send` request will have msg.value equal\n * to the receiverValue specified in the send request.\n *\n * If the invocation of this function reverts or exceeds the gas limit\n * specified by the send requester, this delivery will result in a `ReceiverFailure`.\n *\n * @param payload - an arbitrary message which was included in the delivery by the\n * requester. This message's signature will already have been verified (as long as msg.sender is the Wormhole\n * Relayer contract)\n * @param additionalMessages - Additional messages which were requested to be included in this delivery.\n * Note: There are no contract-level guarantees that the messages in this array are what was requested\n * so **you should verify any sensitive information given here!**\n *\n * For example, if a 'VaaKey' was specified on the source chain, then MAKE SURE the corresponding message here\n * has valid signatures (by calling `parseAndVerifyVM(message)` on the Wormhole core contract)\n *\n * This field can be used to perform and relay TokenBridge or CCTP transfers, and there are example\n * usages of this at\n * https://github.com/wormhole-foundation/hello-token\n * https://github.com/wormhole-foundation/hello-cctp\n *\n * @param sourceAddress - the (wormhole format) address on the sending chain which requested\n * this delivery.\n * @param sourceChain - the wormhole chain ID where this delivery was requested.\n * @param deliveryHash - the VAA hash of the deliveryVAA.\n *\n */\n function receiveWormholeMessages(\n bytes memory payload,\n bytes[] memory additionalMessages,\n bytes32 sourceAddress,\n uint16 sourceChain,\n bytes32 deliveryHash\n ) external payable;\n}\n\nstruct WormholeSource {\n uint16 centrifugeId;\n address addr;\n}\n\nstruct WormholeDestination {\n uint16 wormholeId;\n address addr;\n}\n\ninterface IWormholeAdapter is IAdapter, IWormholeReceiver {\n /// @dev see file() method\n event File(bytes32 indexed what, uint16 fromChainId, uint16 toChainId, address addr);\n\n error FileUnrecognizedParam();\n error NotWormholeRelayer();\n error InvalidSource();\n\n /// @dev Configures the adapter\n /// @param what Can be \"sources\" or \"destinations\".\n /// @param addr if what == \"sources\", it represents the source\n /// @param addr if what == \"destinations\", it represents the destination\n function file(bytes32 what, uint16 centrifugeId, uint16 wormholeId, address addr) external;\n}\n" + }, + "src/common/libraries/MessageLib.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\n\nenum MessageType {\n /// @dev Placeholder for null message type\n _Invalid,\n /// @dev Placeholder for proof message type\n _MessageProof,\n // -- Gateway messages\n InitiateRecovery,\n DisputeRecovery,\n // -- Root messages\n ScheduleUpgrade,\n CancelUpgrade,\n RecoverTokens,\n // -- Pool manager messages\n RegisterAsset,\n NotifyPool,\n NotifyShareClass,\n NotifyPricePoolPerShare,\n NotifyPricePoolPerAsset,\n NotifyShareMetadata,\n UpdateShareHook,\n TransferShares,\n UpdateRestriction,\n UpdateContract,\n ApprovedDeposits,\n IssuedShares,\n RevokedShares,\n // -- Investment manager messages\n DepositRequest,\n RedeemRequest,\n FulfilledDepositRequest,\n FulfilledRedeemRequest,\n CancelDepositRequest,\n CancelRedeemRequest,\n FulfilledCancelDepositRequest,\n FulfilledCancelRedeemRequest,\n // -- BalanceSheet messages\n UpdateHoldingAmount,\n UpdateShares,\n TriggerIssueShares,\n TriggerSubmitQueuedShares,\n TriggerSubmitQueuedAssets,\n SetQueue\n}\n\nenum UpdateRestrictionType {\n /// @dev Placeholder for null update restriction type\n Invalid,\n Member,\n Freeze,\n Unfreeze\n}\n\nenum UpdateContractType {\n /// @dev Placeholder for null update restriction type\n Invalid,\n VaultUpdate,\n UpdateManager,\n MaxAssetPriceAge,\n MaxSharePriceAge,\n Valuation,\n SyncDepositMaxReserve\n}\n\n/// @dev Used internally in the VaultUpdateMessage (not represent a submessage)\nenum VaultUpdateKind {\n DeployAndLink,\n Link,\n Unlink\n}\n\nlibrary MessageLib {\n using MessageLib for bytes;\n using BytesLib for bytes;\n using CastLib for *;\n\n error UnknownMessageType();\n\n /// @dev Encode all message lengths in this constant to avoid a large list of if/elseif checks\n /// and reduce generated bytecode.\n /// If the message has some dynamic part, will be added later in `messageLength()`.\n // forgefmt: disable-next-item\n uint256 constant MESSAGE_LENGTHS_1 =\n (67 << uint8(MessageType.InitiateRecovery) * 8) +\n (67 << uint8(MessageType.DisputeRecovery) * 8) +\n (33 << uint8(MessageType.ScheduleUpgrade) * 8) +\n (33 << uint8(MessageType.CancelUpgrade) * 8) +\n (161 << uint8(MessageType.RecoverTokens) * 8) +\n (18 << uint8(MessageType.RegisterAsset) * 8) +\n (9 << uint8(MessageType.NotifyPool) * 8) +\n (250 << uint8(MessageType.NotifyShareClass) * 8) +\n (49 << uint8(MessageType.NotifyPricePoolPerShare) * 8) +\n (65 << uint8(MessageType.NotifyPricePoolPerAsset) * 8) +\n (185 << uint8(MessageType.NotifyShareMetadata) * 8) +\n (57 << uint8(MessageType.UpdateShareHook) * 8) +\n (73 << uint8(MessageType.TransferShares) * 8) +\n (25 << uint8(MessageType.UpdateRestriction) * 8) +\n (57 << uint8(MessageType.UpdateContract) * 8) +\n (73 << uint8(MessageType.ApprovedDeposits) * 8) +\n (57 << uint8(MessageType.IssuedShares) * 8) +\n (89 << uint8(MessageType.RevokedShares) * 8) +\n (89 << uint8(MessageType.DepositRequest) * 8) +\n (89 << uint8(MessageType.RedeemRequest) * 8) +\n (105 << uint8(MessageType.FulfilledDepositRequest) * 8) +\n (105 << uint8(MessageType.FulfilledRedeemRequest) * 8) +\n (73 << uint8(MessageType.CancelDepositRequest) * 8) +\n (73 << uint8(MessageType.CancelRedeemRequest) * 8) +\n (89 << uint8(MessageType.FulfilledCancelDepositRequest) * 8) +\n (89 << uint8(MessageType.FulfilledCancelRedeemRequest) * 8) +\n (114 << uint8(MessageType.UpdateHoldingAmount) * 8) +\n (50 << uint8(MessageType.UpdateShares) * 8) +\n (73 << uint8(MessageType.TriggerIssueShares) * 8) +\n (25 << uint8(MessageType.TriggerSubmitQueuedShares) * 8);\n\n // forgefmt: disable-next-item\n uint256 constant MESSAGE_LENGTHS_2 =\n (41 << (uint8(MessageType.TriggerSubmitQueuedAssets) - 32) * 8) +\n (26 << (uint8(MessageType.SetQueue) - 32) * 8);\n\n function messageType(bytes memory message) internal pure returns (MessageType) {\n return MessageType(message.toUint8(0));\n }\n\n function messageCode(bytes memory message) internal pure returns (uint8) {\n return message.toUint8(0);\n }\n\n function messageLength(bytes memory message) internal pure returns (uint16 length) {\n uint8 kind = message.toUint8(0);\n require(kind <= uint8(type(MessageType).max), UnknownMessageType());\n\n length = (kind <= 31)\n ? uint16(uint8(bytes32(MESSAGE_LENGTHS_1)[31 - kind]))\n : uint16(uint8(bytes32(MESSAGE_LENGTHS_2)[63 - kind]));\n\n // Spetial treatment for messages with dynamic size:\n if (kind == uint8(MessageType.UpdateRestriction)) {\n length += 2 + message.toUint16(length); //payloadLength\n } else if (kind == uint8(MessageType.UpdateContract)) {\n length += 2 + message.toUint16(length); //payloadLength\n }\n }\n\n function messagePoolId(bytes memory message) internal pure returns (PoolId poolId) {\n uint8 kind = message.toUint8(0);\n\n // All messages from NotifyPool to SetQueue contains a PoolId in position 1.\n if (kind >= uint8(MessageType.NotifyPool) && kind <= uint8(MessageType.SetQueue)) {\n return PoolId.wrap(message.toUint64(1));\n } else {\n return PoolId.wrap(0);\n }\n }\n\n function updateRestrictionType(bytes memory message) internal pure returns (UpdateRestrictionType) {\n return UpdateRestrictionType(message.toUint8(0));\n }\n\n function updateContractType(bytes memory message) internal pure returns (UpdateContractType) {\n return UpdateContractType(message.toUint8(0));\n }\n\n //---------------------------------------\n // InitiateRecovery\n //---------------------------------------\n\n struct InitiateRecovery {\n bytes32 hash;\n bytes32 adapter;\n uint16 centrifugeId;\n }\n\n function deserializeInitiateRecovery(bytes memory data) internal pure returns (InitiateRecovery memory) {\n require(messageType(data) == MessageType.InitiateRecovery, UnknownMessageType());\n return InitiateRecovery({hash: data.toBytes32(1), adapter: data.toBytes32(33), centrifugeId: data.toUint16(65)});\n }\n\n function serialize(InitiateRecovery memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.InitiateRecovery, t.hash, t.adapter, t.centrifugeId);\n }\n\n //---------------------------------------\n // DisputeRecovery\n //---------------------------------------\n\n struct DisputeRecovery {\n bytes32 hash;\n bytes32 adapter;\n uint16 centrifugeId;\n }\n\n function deserializeDisputeRecovery(bytes memory data) internal pure returns (DisputeRecovery memory) {\n require(messageType(data) == MessageType.DisputeRecovery, UnknownMessageType());\n return DisputeRecovery({hash: data.toBytes32(1), adapter: data.toBytes32(33), centrifugeId: data.toUint16(65)});\n }\n\n function serialize(DisputeRecovery memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.DisputeRecovery, t.hash, t.adapter, t.centrifugeId);\n }\n\n //---------------------------------------\n // ScheduleUpgrade\n //---------------------------------------\n\n struct ScheduleUpgrade {\n bytes32 target;\n }\n\n function deserializeScheduleUpgrade(bytes memory data) internal pure returns (ScheduleUpgrade memory) {\n require(messageType(data) == MessageType.ScheduleUpgrade, UnknownMessageType());\n return ScheduleUpgrade({target: data.toBytes32(1)});\n }\n\n function serialize(ScheduleUpgrade memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.ScheduleUpgrade, t.target);\n }\n\n //---------------------------------------\n // CancelUpgrade\n //---------------------------------------\n\n struct CancelUpgrade {\n bytes32 target;\n }\n\n function deserializeCancelUpgrade(bytes memory data) internal pure returns (CancelUpgrade memory) {\n require(messageType(data) == MessageType.CancelUpgrade, UnknownMessageType());\n return CancelUpgrade({target: data.toBytes32(1)});\n }\n\n function serialize(CancelUpgrade memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.CancelUpgrade, t.target);\n }\n\n //---------------------------------------\n // RecoverTokens\n //---------------------------------------\n\n struct RecoverTokens {\n bytes32 target;\n bytes32 token;\n uint256 tokenId;\n bytes32 to;\n uint256 amount;\n }\n\n function deserializeRecoverTokens(bytes memory data) internal pure returns (RecoverTokens memory) {\n require(messageType(data) == MessageType.RecoverTokens, UnknownMessageType());\n return RecoverTokens({\n target: data.toBytes32(1),\n token: data.toBytes32(33),\n tokenId: data.toUint256(65),\n to: data.toBytes32(97),\n amount: data.toUint256(129)\n });\n }\n\n function serialize(RecoverTokens memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.RecoverTokens, t.target, t.token, t.tokenId, t.to, t.amount);\n }\n\n //---------------------------------------\n // RegisterAsset\n //---------------------------------------\n\n struct RegisterAsset {\n uint128 assetId;\n uint8 decimals;\n }\n\n function deserializeRegisterAsset(bytes memory data) internal pure returns (RegisterAsset memory) {\n require(messageType(data) == MessageType.RegisterAsset, UnknownMessageType());\n return RegisterAsset({assetId: data.toUint128(1), decimals: data.toUint8(17)});\n }\n\n function serialize(RegisterAsset memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.RegisterAsset, t.assetId, t.decimals);\n }\n\n //---------------------------------------\n // NotifyPool\n //---------------------------------------\n\n struct NotifyPool {\n uint64 poolId;\n }\n\n function deserializeNotifyPool(bytes memory data) internal pure returns (NotifyPool memory) {\n require(messageType(data) == MessageType.NotifyPool, UnknownMessageType());\n return NotifyPool({poolId: data.toUint64(1)});\n }\n\n function serialize(NotifyPool memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.NotifyPool, t.poolId);\n }\n\n //---------------------------------------\n // NotifyShareClass\n //---------------------------------------\n\n struct NotifyShareClass {\n uint64 poolId;\n bytes16 scId;\n string name; // Fixed to 128 bytes\n bytes32 symbol; // utf8\n uint8 decimals;\n bytes32 salt;\n bytes32 hook;\n }\n\n function deserializeNotifyShareClass(bytes memory data) internal pure returns (NotifyShareClass memory) {\n require(messageType(data) == MessageType.NotifyShareClass, UnknownMessageType());\n return NotifyShareClass({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n name: data.slice(25, 128).bytes128ToString(),\n symbol: data.toBytes32(153),\n decimals: data.toUint8(185),\n salt: data.toBytes32(186),\n hook: data.toBytes32(218)\n });\n }\n\n function serialize(NotifyShareClass memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(\n MessageType.NotifyShareClass,\n t.poolId,\n t.scId,\n bytes(t.name).sliceZeroPadded(0, 128),\n t.symbol,\n t.decimals,\n t.salt,\n t.hook\n );\n }\n\n //---------------------------------------\n // NotifyPricePoolPerShare\n //---------------------------------------\n\n struct NotifyPricePoolPerShare {\n uint64 poolId;\n bytes16 scId;\n uint128 price;\n uint64 timestamp;\n }\n\n function deserializeNotifyPricePoolPerShare(bytes memory data)\n internal\n pure\n returns (NotifyPricePoolPerShare memory)\n {\n require(messageType(data) == MessageType.NotifyPricePoolPerShare, UnknownMessageType());\n return NotifyPricePoolPerShare({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n price: data.toUint128(25),\n timestamp: data.toUint64(41)\n });\n }\n\n function serialize(NotifyPricePoolPerShare memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.NotifyPricePoolPerShare, t.poolId, t.scId, t.price, t.timestamp);\n }\n\n //---------------------------------------\n // NotifyPricePoolPerAsset\n //---------------------------------------\n\n struct NotifyPricePoolPerAsset {\n uint64 poolId;\n bytes16 scId;\n uint128 assetId;\n uint128 price;\n uint64 timestamp;\n }\n\n function deserializeNotifyPricePoolPerAsset(bytes memory data)\n internal\n pure\n returns (NotifyPricePoolPerAsset memory)\n {\n require(messageType(data) == MessageType.NotifyPricePoolPerAsset, UnknownMessageType());\n return NotifyPricePoolPerAsset({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n assetId: data.toUint128(25),\n price: data.toUint128(41),\n timestamp: data.toUint64(57)\n });\n }\n\n function serialize(NotifyPricePoolPerAsset memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.NotifyPricePoolPerAsset, t.poolId, t.scId, t.assetId, t.price, t.timestamp);\n }\n\n //---------------------------------------\n // NotifyShareMetadata\n //---------------------------------------\n\n struct NotifyShareMetadata {\n uint64 poolId;\n bytes16 scId;\n string name; // Fixed to 128 bytes\n bytes32 symbol; // utf8\n }\n\n function deserializeNotifyShareMetadata(bytes memory data) internal pure returns (NotifyShareMetadata memory) {\n require(messageType(data) == MessageType.NotifyShareMetadata, UnknownMessageType());\n return NotifyShareMetadata({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n name: data.slice(25, 128).bytes128ToString(),\n symbol: data.toBytes32(153)\n });\n }\n\n function serialize(NotifyShareMetadata memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(\n MessageType.NotifyShareMetadata, t.poolId, t.scId, bytes(t.name).sliceZeroPadded(0, 128), t.symbol\n );\n }\n\n //---------------------------------------\n // UpdateShareHook\n //---------------------------------------\n\n struct UpdateShareHook {\n uint64 poolId;\n bytes16 scId;\n bytes32 hook;\n }\n\n function deserializeUpdateShareHook(bytes memory data) internal pure returns (UpdateShareHook memory) {\n require(messageType(data) == MessageType.UpdateShareHook, UnknownMessageType());\n return UpdateShareHook({poolId: data.toUint64(1), scId: data.toBytes16(9), hook: data.toBytes32(25)});\n }\n\n function serialize(UpdateShareHook memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.UpdateShareHook, t.poolId, t.scId, t.hook);\n }\n\n //---------------------------------------\n // TransferShares\n //---------------------------------------\n\n struct TransferShares {\n uint64 poolId;\n bytes16 scId;\n bytes32 receiver;\n uint128 amount;\n }\n\n function deserializeTransferShares(bytes memory data) internal pure returns (TransferShares memory) {\n require(messageType(data) == MessageType.TransferShares, UnknownMessageType());\n return TransferShares({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n receiver: data.toBytes32(25),\n amount: data.toUint128(57)\n });\n }\n\n function serialize(TransferShares memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.TransferShares, t.poolId, t.scId, t.receiver, t.amount);\n }\n\n //---------------------------------------\n // UpdateRestriction\n //---------------------------------------\n\n struct UpdateRestriction {\n uint64 poolId;\n bytes16 scId;\n bytes payload; // As sequence of bytes\n }\n\n function deserializeUpdateRestriction(bytes memory data) internal pure returns (UpdateRestriction memory) {\n require(messageType(data) == MessageType.UpdateRestriction, UnknownMessageType());\n\n uint16 payloadLength = data.toUint16(25);\n return UpdateRestriction({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n payload: data.slice(27, payloadLength)\n });\n }\n\n function serialize(UpdateRestriction memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.UpdateRestriction, t.poolId, t.scId, uint16(t.payload.length), t.payload);\n }\n\n //---------------------------------------\n // UpdateRestrictionMember (submsg)\n //---------------------------------------\n\n struct UpdateRestrictionMember {\n bytes32 user;\n uint64 validUntil;\n }\n\n function deserializeUpdateRestrictionMember(bytes memory data)\n internal\n pure\n returns (UpdateRestrictionMember memory)\n {\n require(updateRestrictionType(data) == UpdateRestrictionType.Member, UnknownMessageType());\n\n return UpdateRestrictionMember({user: data.toBytes32(1), validUntil: data.toUint64(33)});\n }\n\n function serialize(UpdateRestrictionMember memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(UpdateRestrictionType.Member, t.user, t.validUntil);\n }\n\n //---------------------------------------\n // UpdateRestrictionFreeze (submsg)\n //---------------------------------------\n\n struct UpdateRestrictionFreeze {\n bytes32 user;\n }\n\n function deserializeUpdateRestrictionFreeze(bytes memory data)\n internal\n pure\n returns (UpdateRestrictionFreeze memory)\n {\n require(updateRestrictionType(data) == UpdateRestrictionType.Freeze, UnknownMessageType());\n\n return UpdateRestrictionFreeze({user: data.toBytes32(1)});\n }\n\n function serialize(UpdateRestrictionFreeze memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(UpdateRestrictionType.Freeze, t.user);\n }\n\n //---------------------------------------\n // UpdateRestrictionUnfreeze (submsg)\n //---------------------------------------\n\n struct UpdateRestrictionUnfreeze {\n bytes32 user;\n }\n\n function deserializeUpdateRestrictionUnfreeze(bytes memory data)\n internal\n pure\n returns (UpdateRestrictionUnfreeze memory)\n {\n require(updateRestrictionType(data) == UpdateRestrictionType.Unfreeze, UnknownMessageType());\n\n return UpdateRestrictionUnfreeze({user: data.toBytes32(1)});\n }\n\n function serialize(UpdateRestrictionUnfreeze memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(UpdateRestrictionType.Unfreeze, t.user);\n }\n\n //---------------------------------------\n // UpdateContract\n //---------------------------------------\n\n struct UpdateContract {\n uint64 poolId;\n bytes16 scId;\n bytes32 target;\n bytes payload; // As sequence of bytes\n }\n\n function deserializeUpdateContract(bytes memory data) internal pure returns (UpdateContract memory) {\n require(messageType(data) == MessageType.UpdateContract, UnknownMessageType());\n uint16 payloadLength = data.toUint16(57);\n return UpdateContract({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n target: data.toBytes32(25),\n payload: data.slice(59, payloadLength)\n });\n }\n\n function serialize(UpdateContract memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(\n MessageType.UpdateContract, t.poolId, t.scId, t.target, uint16(t.payload.length), t.payload\n );\n }\n\n //---------------------------------------\n // UpdateContract.VaultUpdate (submsg)\n //---------------------------------------\n\n struct UpdateContractVaultUpdate {\n bytes32 vaultOrFactory;\n uint128 assetId;\n uint8 kind;\n }\n\n function deserializeUpdateContractVaultUpdate(bytes memory data)\n internal\n pure\n returns (UpdateContractVaultUpdate memory)\n {\n require(updateContractType(data) == UpdateContractType.VaultUpdate, UnknownMessageType());\n\n return UpdateContractVaultUpdate({\n vaultOrFactory: data.toBytes32(1),\n assetId: data.toUint128(33),\n kind: data.toUint8(49)\n });\n }\n\n function serialize(UpdateContractVaultUpdate memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(UpdateContractType.VaultUpdate, t.vaultOrFactory, t.assetId, t.kind);\n }\n\n //---------------------------------------\n // UpdateContract.UpdateManager (submsg)\n //---------------------------------------\n\n struct UpdateContractUpdateManager {\n bytes32 who;\n bool canManage;\n }\n\n function deserializeUpdateContractUpdateManager(bytes memory data)\n internal\n pure\n returns (UpdateContractUpdateManager memory)\n {\n require(updateContractType(data) == UpdateContractType.UpdateManager, UnknownMessageType());\n\n return UpdateContractUpdateManager({who: data.toBytes32(1), canManage: data.toBool(33)});\n }\n\n function serialize(UpdateContractUpdateManager memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(UpdateContractType.UpdateManager, t.who, t.canManage);\n }\n\n //---------------------------------------\n // UpdateContract.MaxAssetPriceAge (submsg)\n //---------------------------------------\n\n struct UpdateContractMaxAssetPriceAge {\n uint128 assetId;\n uint64 maxPriceAge;\n }\n\n function deserializeUpdateContractMaxAssetPriceAge(bytes memory data)\n internal\n pure\n returns (UpdateContractMaxAssetPriceAge memory)\n {\n require(updateContractType(data) == UpdateContractType.MaxAssetPriceAge, UnknownMessageType());\n\n return UpdateContractMaxAssetPriceAge({assetId: data.toUint128(1), maxPriceAge: data.toUint64(17)});\n }\n\n function serialize(UpdateContractMaxAssetPriceAge memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(UpdateContractType.MaxAssetPriceAge, t.assetId, t.maxPriceAge);\n }\n\n //---------------------------------------\n // UpdateContract.MaxSharePriceAge (submsg)\n //---------------------------------------\n\n struct UpdateContractMaxSharePriceAge {\n uint64 maxPriceAge;\n }\n\n function deserializeUpdateContractMaxSharePriceAge(bytes memory data)\n internal\n pure\n returns (UpdateContractMaxSharePriceAge memory)\n {\n require(updateContractType(data) == UpdateContractType.MaxSharePriceAge, UnknownMessageType());\n\n return UpdateContractMaxSharePriceAge({maxPriceAge: data.toUint64(1)});\n }\n\n function serialize(UpdateContractMaxSharePriceAge memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(UpdateContractType.MaxSharePriceAge, t.maxPriceAge);\n }\n\n //---------------------------------------\n // UpdateContract.Valuation (submsg)\n //---------------------------------------\n\n struct UpdateContractValuation {\n bytes32 valuation;\n }\n\n function deserializeUpdateContractValuation(bytes memory data)\n internal\n pure\n returns (UpdateContractValuation memory)\n {\n require(updateContractType(data) == UpdateContractType.Valuation, UnknownMessageType());\n\n return UpdateContractValuation({valuation: data.toBytes32(1)});\n }\n\n function serialize(UpdateContractValuation memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(UpdateContractType.Valuation, t.valuation);\n }\n\n //---------------------------------------\n // UpdateContract.SyncDepositMaxReserve (submsg)\n //---------------------------------------\n\n struct UpdateContractSyncDepositMaxReserve {\n uint128 assetId;\n uint128 maxReserve;\n }\n\n function deserializeUpdateContractSyncDepositMaxReserve(bytes memory data)\n internal\n pure\n returns (UpdateContractSyncDepositMaxReserve memory)\n {\n require(updateContractType(data) == UpdateContractType.SyncDepositMaxReserve, UnknownMessageType());\n\n return UpdateContractSyncDepositMaxReserve({assetId: data.toUint128(1), maxReserve: data.toUint128(17)});\n }\n\n function serialize(UpdateContractSyncDepositMaxReserve memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(UpdateContractType.SyncDepositMaxReserve, t.assetId, t.maxReserve);\n }\n\n //---------------------------------------\n // DepositRequest\n //---------------------------------------\n\n struct DepositRequest {\n uint64 poolId;\n bytes16 scId;\n bytes32 investor;\n uint128 assetId;\n uint128 amount;\n }\n\n function deserializeDepositRequest(bytes memory data) internal pure returns (DepositRequest memory) {\n require(messageType(data) == MessageType.DepositRequest, UnknownMessageType());\n return DepositRequest({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n investor: data.toBytes32(25),\n assetId: data.toUint128(57),\n amount: data.toUint128(73)\n });\n }\n\n function serialize(DepositRequest memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.DepositRequest, t.poolId, t.scId, t.investor, t.assetId, t.amount);\n }\n\n //---------------------------------------\n // RedeemRequest\n //---------------------------------------\n\n struct RedeemRequest {\n uint64 poolId;\n bytes16 scId;\n bytes32 investor;\n uint128 assetId;\n uint128 amount;\n }\n\n function deserializeRedeemRequest(bytes memory data) internal pure returns (RedeemRequest memory) {\n require(messageType(data) == MessageType.RedeemRequest, UnknownMessageType());\n return RedeemRequest({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n investor: data.toBytes32(25),\n assetId: data.toUint128(57),\n amount: data.toUint128(73)\n });\n }\n\n function serialize(RedeemRequest memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.RedeemRequest, t.poolId, t.scId, t.investor, t.assetId, t.amount);\n }\n\n //---------------------------------------\n // CancelDepositRequest\n //---------------------------------------\n\n struct CancelDepositRequest {\n uint64 poolId;\n bytes16 scId;\n bytes32 investor;\n uint128 assetId;\n }\n\n function deserializeCancelDepositRequest(bytes memory data) internal pure returns (CancelDepositRequest memory) {\n require(messageType(data) == MessageType.CancelDepositRequest, UnknownMessageType());\n return CancelDepositRequest({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n investor: data.toBytes32(25),\n assetId: data.toUint128(57)\n });\n }\n\n function serialize(CancelDepositRequest memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.CancelDepositRequest, t.poolId, t.scId, t.investor, t.assetId);\n }\n\n //---------------------------------------\n // CancelRedeemRequest\n //---------------------------------------\n\n struct CancelRedeemRequest {\n uint64 poolId;\n bytes16 scId;\n bytes32 investor;\n uint128 assetId;\n }\n\n function deserializeCancelRedeemRequest(bytes memory data) internal pure returns (CancelRedeemRequest memory) {\n require(messageType(data) == MessageType.CancelRedeemRequest, UnknownMessageType());\n return CancelRedeemRequest({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n investor: data.toBytes32(25),\n assetId: data.toUint128(57)\n });\n }\n\n function serialize(CancelRedeemRequest memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.CancelRedeemRequest, t.poolId, t.scId, t.investor, t.assetId);\n }\n\n //---------------------------------------\n // FulfilledDepositRequest\n //---------------------------------------\n\n struct FulfilledDepositRequest {\n uint64 poolId;\n bytes16 scId;\n bytes32 investor;\n uint128 assetId;\n uint128 assetAmount;\n uint128 shareAmount;\n }\n\n function deserializeFulfilledDepositRequest(bytes memory data)\n internal\n pure\n returns (FulfilledDepositRequest memory)\n {\n require(messageType(data) == MessageType.FulfilledDepositRequest, UnknownMessageType());\n return FulfilledDepositRequest({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n investor: data.toBytes32(25),\n assetId: data.toUint128(57),\n assetAmount: data.toUint128(73),\n shareAmount: data.toUint128(89)\n });\n }\n\n function serialize(FulfilledDepositRequest memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(\n MessageType.FulfilledDepositRequest, t.poolId, t.scId, t.investor, t.assetId, t.assetAmount, t.shareAmount\n );\n }\n\n //---------------------------------------\n // FulfilledRedeemRequest\n //---------------------------------------\n\n struct FulfilledRedeemRequest {\n uint64 poolId;\n bytes16 scId;\n bytes32 investor;\n uint128 assetId;\n uint128 assetAmount;\n uint128 shareAmount;\n }\n\n function deserializeFulfilledRedeemRequest(bytes memory data)\n internal\n pure\n returns (FulfilledRedeemRequest memory)\n {\n require(messageType(data) == MessageType.FulfilledRedeemRequest, UnknownMessageType());\n return FulfilledRedeemRequest({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n investor: data.toBytes32(25),\n assetId: data.toUint128(57),\n assetAmount: data.toUint128(73),\n shareAmount: data.toUint128(89)\n });\n }\n\n function serialize(FulfilledRedeemRequest memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(\n MessageType.FulfilledRedeemRequest, t.poolId, t.scId, t.investor, t.assetId, t.assetAmount, t.shareAmount\n );\n }\n\n //---------------------------------------\n // FulfilledCancelDepositRequest\n //---------------------------------------\n\n struct FulfilledCancelDepositRequest {\n uint64 poolId;\n bytes16 scId;\n bytes32 investor;\n uint128 assetId;\n uint128 cancelledAmount;\n }\n\n function deserializeFulfilledCancelDepositRequest(bytes memory data)\n internal\n pure\n returns (FulfilledCancelDepositRequest memory)\n {\n require(messageType(data) == MessageType.FulfilledCancelDepositRequest, UnknownMessageType());\n return FulfilledCancelDepositRequest({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n investor: data.toBytes32(25),\n assetId: data.toUint128(57),\n cancelledAmount: data.toUint128(73)\n });\n }\n\n function serialize(FulfilledCancelDepositRequest memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(\n MessageType.FulfilledCancelDepositRequest, t.poolId, t.scId, t.investor, t.assetId, t.cancelledAmount\n );\n }\n\n //---------------------------------------\n // FulfilledCancelRedeemRequest\n //---------------------------------------\n\n struct FulfilledCancelRedeemRequest {\n uint64 poolId;\n bytes16 scId;\n bytes32 investor;\n uint128 assetId;\n uint128 cancelledShares;\n }\n\n function deserializeFulfilledCancelRedeemRequest(bytes memory data)\n internal\n pure\n returns (FulfilledCancelRedeemRequest memory)\n {\n require(messageType(data) == MessageType.FulfilledCancelRedeemRequest, UnknownMessageType());\n return FulfilledCancelRedeemRequest({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n investor: data.toBytes32(25),\n assetId: data.toUint128(57),\n cancelledShares: data.toUint128(73)\n });\n }\n\n function serialize(FulfilledCancelRedeemRequest memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(\n MessageType.FulfilledCancelRedeemRequest, t.poolId, t.scId, t.investor, t.assetId, t.cancelledShares\n );\n }\n\n //---------------------------------------\n // UpdateHoldingAmount\n //---------------------------------------\n\n struct UpdateHoldingAmount {\n uint64 poolId;\n bytes16 scId;\n uint128 assetId;\n bytes32 who;\n uint128 amount;\n uint128 pricePerUnit;\n uint64 timestamp;\n bool isIncrease; // Signals whether this is an increase or a decrease\n }\n\n function deserializeUpdateHoldingAmount(bytes memory data) internal pure returns (UpdateHoldingAmount memory h) {\n require(messageType(data) == MessageType.UpdateHoldingAmount, \"UnknownMessageType\");\n\n return UpdateHoldingAmount({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n assetId: data.toUint128(25),\n who: data.toBytes32(41),\n amount: data.toUint128(73),\n pricePerUnit: data.toUint128(89),\n timestamp: data.toUint64(105),\n isIncrease: data.toBool(113)\n });\n }\n\n function serialize(UpdateHoldingAmount memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(\n MessageType.UpdateHoldingAmount,\n t.poolId,\n t.scId,\n t.assetId,\n t.who,\n t.amount,\n t.pricePerUnit,\n t.timestamp,\n t.isIncrease\n );\n }\n\n //---------------------------------------\n // UpdateShares\n //---------------------------------------\n\n struct UpdateShares {\n uint64 poolId;\n bytes16 scId;\n uint128 shares;\n uint64 timestamp;\n bool isIssuance;\n }\n\n function deserializeUpdateShares(bytes memory data) internal pure returns (UpdateShares memory) {\n require(messageType(data) == MessageType.UpdateShares, UnknownMessageType());\n\n return UpdateShares({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n shares: data.toUint128(25),\n timestamp: data.toUint64(41),\n isIssuance: data.toBool(49)\n });\n }\n\n function serialize(UpdateShares memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.UpdateShares, t.poolId, t.scId, t.shares, t.timestamp, t.isIssuance);\n }\n\n //---------------------------------------\n // ApprovedDeposits\n //---------------------------------------\n\n struct ApprovedDeposits {\n uint64 poolId;\n bytes16 scId;\n uint128 assetId;\n uint128 assetAmount;\n uint128 pricePoolPerAsset;\n }\n\n function deserializeApprovedDeposits(bytes memory data) internal pure returns (ApprovedDeposits memory) {\n require(messageType(data) == MessageType.ApprovedDeposits, UnknownMessageType());\n\n return ApprovedDeposits({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n assetId: data.toUint128(25),\n assetAmount: data.toUint128(41),\n pricePoolPerAsset: data.toUint128(57)\n });\n }\n\n function serialize(ApprovedDeposits memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(\n MessageType.ApprovedDeposits, t.poolId, t.scId, t.assetId, t.assetAmount, t.pricePoolPerAsset\n );\n }\n\n //---------------------------------------\n // IssuedShares\n //---------------------------------------\n\n struct IssuedShares {\n uint64 poolId;\n bytes16 scId;\n uint128 shareAmount;\n uint128 pricePoolPerShare;\n }\n\n function deserializeIssuedShares(bytes memory data) internal pure returns (IssuedShares memory) {\n require(messageType(data) == MessageType.IssuedShares, UnknownMessageType());\n\n return IssuedShares({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n shareAmount: data.toUint128(25),\n pricePoolPerShare: data.toUint128(41)\n });\n }\n\n function serialize(IssuedShares memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.IssuedShares, t.poolId, t.scId, t.shareAmount, t.pricePoolPerShare);\n }\n\n //---------------------------------------\n // RevokedShares\n //---------------------------------------\n\n struct RevokedShares {\n uint64 poolId;\n bytes16 scId;\n uint128 assetId;\n uint128 shareAmount;\n uint128 pricePoolPerShare;\n uint128 assetAmount;\n }\n\n function deserializeRevokedShares(bytes memory data) internal pure returns (RevokedShares memory) {\n require(messageType(data) == MessageType.RevokedShares, UnknownMessageType());\n\n return RevokedShares({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n assetId: data.toUint128(25),\n assetAmount: data.toUint128(41),\n shareAmount: data.toUint128(57),\n pricePoolPerShare: data.toUint128(73)\n });\n }\n\n function serialize(RevokedShares memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(\n MessageType.RevokedShares, t.poolId, t.scId, t.assetId, t.assetAmount, t.shareAmount, t.pricePoolPerShare\n );\n }\n\n //---------------------------------------\n // TriggerIssueShares\n //---------------------------------------\n\n struct TriggerIssueShares {\n uint64 poolId;\n bytes16 scId;\n bytes32 who;\n uint128 shares;\n }\n\n function deserializeTriggerIssueShares(bytes memory data) internal pure returns (TriggerIssueShares memory) {\n require(messageType(data) == MessageType.TriggerIssueShares, UnknownMessageType());\n\n return TriggerIssueShares({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n who: data.toBytes32(25),\n shares: data.toUint128(57)\n });\n }\n\n function serialize(TriggerIssueShares memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.TriggerIssueShares, t.poolId, t.scId, t.who, t.shares);\n }\n\n //---------------------------------------\n // TriggerSubmitQueuedShares\n //---------------------------------------\n\n struct TriggerSubmitQueuedShares {\n uint64 poolId;\n bytes16 scId;\n }\n\n function deserializeTriggerSubmitQueuedShares(bytes memory data)\n internal\n pure\n returns (TriggerSubmitQueuedShares memory)\n {\n require(messageType(data) == MessageType.TriggerSubmitQueuedShares, UnknownMessageType());\n return TriggerSubmitQueuedShares({poolId: data.toUint64(1), scId: data.toBytes16(9)});\n }\n\n function serialize(TriggerSubmitQueuedShares memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.TriggerSubmitQueuedShares, t.poolId, t.scId);\n }\n\n //---------------------------------------\n // TriggerSubmitQueuedAssets\n //---------------------------------------\n\n struct TriggerSubmitQueuedAssets {\n uint64 poolId;\n bytes16 scId;\n uint128 assetId;\n }\n\n function deserializeTriggerSubmitQueuedAssets(bytes memory data)\n internal\n pure\n returns (TriggerSubmitQueuedAssets memory)\n {\n require(messageType(data) == MessageType.TriggerSubmitQueuedAssets, UnknownMessageType());\n return\n TriggerSubmitQueuedAssets({poolId: data.toUint64(1), scId: data.toBytes16(9), assetId: data.toUint128(25)});\n }\n\n function serialize(TriggerSubmitQueuedAssets memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.TriggerSubmitQueuedAssets, t.poolId, t.scId, t.assetId);\n }\n\n //---------------------------------------\n // SetQueue\n //---------------------------------------\n\n struct SetQueue {\n uint64 poolId;\n bytes16 scId;\n bool enabled;\n }\n\n function deserializeSetQueue(bytes memory data) internal pure returns (SetQueue memory) {\n require(messageType(data) == MessageType.SetQueue, UnknownMessageType());\n return SetQueue({poolId: data.toUint64(1), scId: data.toBytes16(9), enabled: data.toBool(25)});\n }\n\n function serialize(SetQueue memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.SetQueue, t.poolId, t.scId, t.enabled);\n }\n}\n" + }, + "src/common/libraries/MessageProofLib.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\n\nlibrary MessageProofLib {\n using BytesLib for bytes;\n\n uint8 constant MESSAGE_PROOF_ID = 1;\n\n error UnknownMessageProofType();\n\n function deserializeMessageProof(bytes memory data) internal pure returns (bytes32) {\n require(data.toUint8(0) == MESSAGE_PROOF_ID, UnknownMessageProofType());\n return data.toBytes32(1);\n }\n\n function serializeMessageProof(bytes32 hash) internal pure returns (bytes memory) {\n return abi.encodePacked(MESSAGE_PROOF_ID, hash);\n }\n}\n" + }, + "src/common/libraries/PricingLib.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {IERC20Metadata} from \"src/misc/interfaces/IERC20.sol\";\nimport {IERC6909MetadataExt} from \"src/misc/interfaces/IERC6909.sol\";\nimport {D18, d18} from \"src/misc/types/D18.sol\";\n\nimport {PricingLib} from \"src/common/libraries/PricingLib.sol\";\n\nlibrary PricingLib {\n using MathLib for *;\n\n /// @dev Prices are fixed-point integers with 18 decimals\n uint8 internal constant PRICE_DECIMALS = 18;\n\n /// -----------------------------------------------------\n /// View Methods\n /// -----------------------------------------------------\n\n /// @dev Converts the given asset amount to share amount. Returned value is in share decimals.\n ///\n /// @dev NOTE: MUST ONLY be used in AsyncRequestManager which rely on priceAssetPerShare that is derived from\n /// Fulfilled*\n /// message amounts. Any other codepath must use the variant with pricePoolPerAsset and pricePoolPerShare\n function assetToShareAmount(\n address shareToken,\n address asset,\n uint256 tokenId,\n uint128 assetAmount,\n D18 priceAssetPerShare_,\n MathLib.Rounding rounding\n ) internal view returns (uint128 shares) {\n if (assetAmount == 0 || priceAssetPerShare_.raw() == 0) {\n return 0;\n }\n\n uint8 assetDecimals = getAssetDecimals(asset, tokenId);\n uint8 shareDecimals = IERC20Metadata(shareToken).decimals();\n\n return PricingLib.convertWithReciprocalPrice(\n assetAmount, assetDecimals, shareDecimals, priceAssetPerShare_, rounding\n ).toUint128();\n }\n\n /// @dev Converts the given asset amount to share amount. Returned value is in share decimals.\n function assetToShareAmount(\n address shareToken,\n address asset,\n uint256 tokenId,\n uint128 assetAmount,\n D18 pricePoolPerAsset,\n D18 pricePoolPerShare,\n MathLib.Rounding rounding\n ) internal view returns (uint128 shares) {\n if (assetAmount == 0 || pricePoolPerShare.raw() == 0 || pricePoolPerAsset.raw() == 0) {\n return 0;\n }\n\n uint8 assetDecimals = getAssetDecimals(asset, tokenId);\n uint8 shareDecimals = IERC20Metadata(shareToken).decimals();\n\n return PricingLib.assetToShareAmount(\n assetAmount, assetDecimals, shareDecimals, pricePoolPerAsset, pricePoolPerShare, rounding\n ).toUint128();\n }\n\n /// @dev Converts the given share amount to asset amount. Returned value is in share decimals.\n ///\n /// @dev NOTE: MUST ONLY be used in AsyncRequestManager which rely on priceAssetPerShare that is derived from\n /// Fulfilled*\n /// message amounts. Any other codepath must use the variant with pricePoolPerAsset and pricePoolPerShare\n function shareToAssetAmount(\n address shareToken,\n uint128 shareAmount,\n address asset,\n uint256 tokenId,\n D18 priceAssetPerShare_,\n MathLib.Rounding rounding\n ) internal view returns (uint128 shares) {\n if (shareAmount == 0 || priceAssetPerShare_.raw() == 0) {\n return 0;\n }\n\n uint8 assetDecimals = getAssetDecimals(asset, tokenId);\n uint8 shareDecimals = IERC20Metadata(shareToken).decimals();\n\n return PricingLib.convertWithPrice(shareAmount, shareDecimals, assetDecimals, priceAssetPerShare_, rounding)\n .toUint128();\n }\n\n /// @dev Converts the given share amount to asset amount. Returned value is in share decimals.\n function shareToAssetAmount(\n address shareToken,\n uint128 shareAmount,\n address asset,\n uint256 tokenId,\n D18 pricePoolPerAsset,\n D18 pricePoolPerShare,\n MathLib.Rounding rounding\n ) internal view returns (uint128 shares) {\n if (shareAmount == 0 || pricePoolPerShare.raw() == 0 || pricePoolPerAsset.raw() == 0) {\n return 0;\n }\n\n uint8 assetDecimals = getAssetDecimals(asset, tokenId);\n uint8 shareDecimals = IERC20Metadata(shareToken).decimals();\n\n return PricingLib.shareToAssetAmount(\n shareAmount, shareDecimals, assetDecimals, pricePoolPerAsset, pricePoolPerShare, rounding\n ).toUint128();\n }\n\n /// @dev Calculates the asset price per share returns the value in price decimals\n /// Denominated in ASSET_UNIT/SHARE_UNIT\n function calculatePriceAssetPerShare(\n address shareToken,\n uint128 shares,\n address asset,\n uint256 tokenId,\n uint128 assets,\n MathLib.Rounding rounding\n ) internal view returns (uint256 priceAssetPerShare_) {\n if (assets == 0 || shares == 0) {\n return 0;\n }\n\n uint8 assetDecimals = getAssetDecimals(asset, tokenId);\n uint8 shareDecimals = IERC20Metadata(shareToken).decimals();\n\n // NOTE: More precise than d18(assets * 10 ** assetDecimals, shares * 10 ** shareDecimals)\n return toPriceDecimals(assets, assetDecimals).mulDiv(\n 10 ** PRICE_DECIMALS, toPriceDecimals(shares, shareDecimals), rounding\n );\n }\n\n /// -----------------------------------------------------\n /// Pure Methods\n /// -----------------------------------------------------\n\n /// @dev Converts an amount using decimals and price with implicit rounding down\n function convertWithPrice(uint256 baseAmount, uint8 baseDecimals, uint8 quoteDecimals, D18 priceQuotePerBase)\n internal\n pure\n returns (uint256 quoteAmount)\n {\n return convertWithPrice(baseAmount, baseDecimals, quoteDecimals, priceQuotePerBase, MathLib.Rounding.Down);\n }\n\n /// @dev Converts an amount using decimals and price with explicit rounding.\n function convertWithPrice(\n uint256 baseAmount,\n uint8 baseDecimals,\n uint8 quoteDecimals,\n D18 priceQuotePerBase,\n MathLib.Rounding rounding\n ) internal pure returns (uint256 quoteAmount) {\n if (baseDecimals == quoteDecimals) {\n return priceQuotePerBase.mulUint256(baseAmount, rounding);\n }\n\n return\n priceQuotePerBase.mulUint256(MathLib.mulDiv(baseAmount, 10 ** quoteDecimals, 10 ** baseDecimals), rounding);\n }\n\n /// @dev Converts an amount using decimals and reciprocal price.\n ///\n /// NOTE: More precise than convertWithPrice(,,,price.reciprocal,)\n function convertWithReciprocalPrice(\n uint256 baseAmount,\n uint8 baseDecimals,\n uint8 quoteDecimals,\n D18 priceBasePerQuote,\n MathLib.Rounding rounding\n ) internal pure returns (uint256 quoteAmount) {\n if (baseDecimals == quoteDecimals) {\n return priceBasePerQuote.reciprocalMulUint256(baseAmount, rounding);\n }\n\n return priceBasePerQuote.reciprocalMulUint256(\n MathLib.mulDiv(baseAmount, 10 ** quoteDecimals, 10 ** baseDecimals), rounding\n );\n }\n\n /// @dev Converts asset amount to share amount.\n function assetToShareAmount(\n uint256 assetAmount,\n uint8 assetDecimals,\n uint8 shareDecimals,\n D18 pricePoolPerAsset,\n D18 pricePoolPerShare,\n MathLib.Rounding rounding\n ) internal pure returns (uint256 shareAmount) {\n return pricePoolPerShare.reciprocalMulUint256(\n convertWithPrice(assetAmount, assetDecimals, shareDecimals, pricePoolPerAsset, MathLib.Rounding.Down),\n rounding\n );\n }\n\n /// @dev Converts share amount to asset asset amount.\n function shareToAssetAmount(\n uint256 shareAmount,\n uint8 shareDecimals,\n uint8 assetDecimals,\n D18 pricePoolPerAsset,\n D18 pricePoolPerShare,\n MathLib.Rounding rounding\n ) internal pure returns (uint256 assetAmount) {\n return convertWithReciprocalPrice(\n pricePoolPerShare.mulUint256(shareAmount, MathLib.Rounding.Down),\n shareDecimals,\n assetDecimals,\n pricePoolPerAsset,\n rounding\n );\n }\n\n /// @dev Converts pool amount to asset amount.\n function poolToAssetAmount(\n uint256 poolAmount,\n uint8 poolDecimals,\n uint8 assetDecimals,\n D18 pricePoolPerAsset,\n MathLib.Rounding rounding\n ) internal pure returns (uint256 assetAmount) {\n return convertWithReciprocalPrice(poolAmount, poolDecimals, assetDecimals, pricePoolPerAsset, rounding);\n }\n\n /// @dev Returns the asset price per share denominated in ASSET_UNIT/SHARE_UNIT\n ///\n /// @dev NOTE: Should never be used for calculating amounts due to precision loss. Instead, please refer to\n /// conversion relying on pricePoolPerShare and pricePoolPerAsset.\n function priceAssetPerShare(D18 pricePoolPerShare, D18 pricePoolPerAsset)\n internal\n pure\n returns (D18 priceAssetPerShare_)\n {\n return pricePoolPerShare / pricePoolPerAsset;\n }\n\n /// -----------------------------------------------------\n /// Private Methods\n /// -----------------------------------------------------\n\n /// @dev Returns the asset decimals\n function getAssetDecimals(address asset, uint256 tokenId) private view returns (uint8 assetDecimals) {\n return tokenId == 0 ? IERC20Metadata(asset).decimals() : IERC6909MetadataExt(asset).decimals(tokenId);\n }\n\n /// @dev When converting assets to shares using the price, all values are normalized to PRICE_DECIMALS\n /// @dev NOTE: We require all assets to have 2 <= decimals <= 18, see `PoolManager.registerAsset`\n function toPriceDecimals(uint128 _value, uint8 decimals) private pure returns (uint256) {\n if (PRICE_DECIMALS == decimals) return uint256(_value);\n return uint256(_value) * 10 ** (PRICE_DECIMALS - decimals);\n }\n\n /// @dev Converts decimals of the value from the price decimals back to the intended decimals\n /// @dev NOTE: We require all assets to have 2 <= decimals <= 18, see `PoolManager.registerAsset`\n function fromPriceDecimals(uint256 _value, uint8 decimals) private pure returns (uint128) {\n if (PRICE_DECIMALS == decimals) return _value.toUint128();\n return (_value / 10 ** (PRICE_DECIMALS - decimals)).toUint128();\n }\n}\n" + }, + "src/common/types/AccountId.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\ntype AccountId is uint32;\n\nfunction raw(AccountId accountId_) pure returns (uint32) {\n return AccountId.unwrap(accountId_);\n}\n\nusing {raw} for AccountId global;\n" + }, + "src/common/types/AssetId.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\n/// @dev Composite Id of the centrifugeId (uint16) where the asset resides\n/// and a local counter (uint64) that is part of the contract that registers the asset.\ntype AssetId is uint128;\n\nfunction isNull(AssetId assetId) pure returns (bool) {\n return AssetId.unwrap(assetId) == 0;\n}\n\nfunction addr(AssetId assetId) pure returns (address) {\n return address(uint160(AssetId.unwrap(assetId)));\n}\n\nfunction raw(AssetId assetId) pure returns (uint128) {\n return AssetId.unwrap(assetId);\n}\n\nfunction centrifugeId(AssetId assetId) pure returns (uint16) {\n return uint16(AssetId.unwrap(assetId) >> 112);\n}\n\nfunction newAssetId(uint16 centrifugeId_, uint64 counter) pure returns (AssetId) {\n return AssetId.wrap((uint128(centrifugeId_) << 112) + counter);\n}\n\nfunction newAssetId(uint32 isoCode) pure returns (AssetId) {\n return AssetId.wrap(isoCode);\n}\n\nfunction eq(AssetId a, AssetId b) pure returns (bool) {\n return a.raw() == b.raw();\n}\n\nusing {isNull, addr, raw, centrifugeId, eq} for AssetId global;\n" + }, + "src/common/types/PoolId.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\n\nusing MathLib for uint256;\n\ntype PoolId is uint64;\n\nfunction centrifugeId(PoolId poolId) pure returns (uint16) {\n return uint16(PoolId.unwrap(poolId) >> 48);\n}\n\nfunction newPoolId(uint16 centrifugeId_, uint48 localPoolId) pure returns (PoolId) {\n return PoolId.wrap((uint64(centrifugeId_) << 48) | uint64(localPoolId));\n}\n\nfunction isNull(PoolId poolId) pure returns (bool) {\n return PoolId.unwrap(poolId) == 0;\n}\n\nfunction raw(PoolId poolId) pure returns (uint64) {\n return PoolId.unwrap(poolId);\n}\n\nusing {centrifugeId, isNull, raw} for PoolId global;\n" + }, + "src/common/types/ShareClassId.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\n\ntype ShareClassId is bytes16;\n\nfunction isNull(ShareClassId scId) pure returns (bool) {\n return ShareClassId.unwrap(scId) == 0;\n}\n\nfunction equals(ShareClassId left, ShareClassId right) pure returns (bool) {\n return ShareClassId.unwrap(left) == ShareClassId.unwrap(right);\n}\n\nfunction raw(ShareClassId scId) pure returns (bytes16) {\n return ShareClassId.unwrap(scId);\n}\n\nfunction newShareClassId(PoolId poolId, uint32 index) pure returns (ShareClassId scId) {\n return ShareClassId.wrap(bytes16((uint128(PoolId.unwrap(poolId)) << 64) + index));\n}\n\nusing {isNull, raw, equals as ==} for ShareClassId global;\n" + }, + "src/hooks/FreezeOnly.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\nimport {BitmapLib} from \"src/misc/libraries/BitmapLib.sol\";\nimport {IERC165} from \"src/misc/interfaces/IERC7575.sol\";\n\nimport {IRoot} from \"src/common/interfaces/IRoot.sol\";\nimport {UpdateRestrictionType, MessageLib} from \"src/common/libraries/MessageLib.sol\";\n\nimport {IHook, HookData} from \"src/common/interfaces/IHook.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\n\nimport {IFreezable} from \"src/hooks/interfaces/IFreezable.sol\";\n\n/// @title Freeze Only\n/// @notice Hook implementation that:\n/// * Allows any non-frozen account to receive tokens and transfer tokens\n/// * Supports freezing accounts which blocks transfers both to and from them\n/// * Allows authTransferFrom calls\n///\n/// @dev The last bit of hookData is used to denote whether the account is frozen.\ncontract FreezeOnly is Auth, IFreezable, IHook {\n using BitmapLib for *;\n using MessageLib for *;\n using BytesLib for bytes;\n using CastLib for bytes32;\n\n /// @dev Least significant bit\n uint8 public constant FREEZE_BIT = 0;\n\n IRoot public immutable root;\n\n constructor(address root_, address deployer) Auth(deployer) {\n root = IRoot(root_);\n }\n\n //----------------------------------------------------------------------------------------------\n // Callback from share token\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHook\n function onERC20Transfer(address from, address to, uint256 value, HookData calldata hookData)\n external\n virtual\n returns (bytes4)\n {\n require(checkERC20Transfer(from, to, value, hookData), TransferBlocked());\n return IHook.onERC20Transfer.selector;\n }\n\n /// @inheritdoc IHook\n function onERC20AuthTransfer(\n address, /* sender */\n address, /* from */\n address, /* to */\n uint256, /* value */\n HookData calldata /* hookData */\n ) external pure returns (bytes4) {\n return IHook.onERC20AuthTransfer.selector;\n }\n\n /// @inheritdoc IHook\n function checkERC20Transfer(address from, address, /* to */ uint256, /* value */ HookData calldata hookData)\n public\n view\n returns (bool)\n {\n uint128 fromHookData = uint128(hookData.from);\n if (fromHookData.getBit(FREEZE_BIT) == true && !root.endorsed(from)) {\n // Source is frozen and not endorsed\n return false;\n }\n\n uint128 toHookData = uint128(hookData.to);\n if (toHookData.getBit(FREEZE_BIT) == true) {\n // Destination is frozen\n return false;\n }\n\n return true;\n }\n\n //----------------------------------------------------------------------------------------------\n // Restriction updates\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHook\n function updateRestriction(address token, bytes memory payload) external auth {\n UpdateRestrictionType updateId = payload.updateRestrictionType();\n\n if (updateId == UpdateRestrictionType.Freeze) {\n MessageLib.UpdateRestrictionFreeze memory m = payload.deserializeUpdateRestrictionFreeze();\n freeze(token, m.user.toAddress());\n } else if (updateId == UpdateRestrictionType.Unfreeze) {\n MessageLib.UpdateRestrictionUnfreeze memory m = payload.deserializeUpdateRestrictionUnfreeze();\n unfreeze(token, m.user.toAddress());\n } else {\n revert InvalidUpdate();\n }\n }\n\n /// @inheritdoc IFreezable\n function freeze(address token, address user) public auth {\n require(user != address(0), CannotFreezeZeroAddress());\n require(!root.endorsed(user), EndorsedUserCannotBeFrozen());\n\n uint128 hookData = uint128(IShareToken(token).hookDataOf(user));\n IShareToken(token).setHookData(user, bytes16(hookData.setBit(FREEZE_BIT, true)));\n\n emit Freeze(token, user);\n }\n\n /// @inheritdoc IFreezable\n function unfreeze(address token, address user) public auth {\n uint128 hookData = uint128(IShareToken(token).hookDataOf(user));\n IShareToken(token).setHookData(user, bytes16(hookData.setBit(FREEZE_BIT, false)));\n\n emit Unfreeze(token, user);\n }\n\n /// @inheritdoc IFreezable\n function isFrozen(address token, address user) public view returns (bool) {\n return uint128(IShareToken(token).hookDataOf(user)).getBit(FREEZE_BIT);\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-165\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC165\n function supportsInterface(bytes4 interfaceId) external pure override returns (bool) {\n return interfaceId == type(IHook).interfaceId || interfaceId == type(IERC165).interfaceId;\n }\n}\n" + }, + "src/hooks/FullRestrictions.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {BitmapLib} from \"src/misc/libraries/BitmapLib.sol\";\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\nimport {IERC165} from \"src/misc/interfaces/IERC7575.sol\";\n\nimport {UpdateRestrictionType, MessageLib} from \"src/common/libraries/MessageLib.sol\";\nimport {IRoot} from \"src/common/interfaces/IRoot.sol\";\n\nimport {IHook, HookData, ESCROW_HOOK_ID} from \"src/common/interfaces/IHook.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\n\nimport {IFreezable} from \"src/hooks/interfaces/IFreezable.sol\";\nimport {IMemberlist} from \"src/hooks/interfaces/IMemberlist.sol\";\n\n/// @title Full Restrictions\n/// @notice Hook implementation that:\n/// * Requires adding accounts to the memberlist before they can receive tokens\n/// * Supports freezing accounts which blocks transfers both to and from them\n/// * Allows authTransferFrom calls\n///\n/// @dev The first 8 bytes (uint64) of hookData is used for the memberlist valid until date,\n/// the last bit is used to denote whether the account is frozen.\ncontract FullRestrictions is Auth, IMemberlist, IFreezable, IHook {\n using BitmapLib for *;\n using MessageLib for *;\n using BytesLib for bytes;\n using CastLib for bytes32;\n\n /// @dev Least significant bit\n uint8 public constant FREEZE_BIT = 0;\n\n IRoot public immutable root;\n\n constructor(address root_, address deployer) Auth(deployer) {\n root = IRoot(root_);\n }\n\n //----------------------------------------------------------------------------------------------\n // Callback from share token\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHook\n function onERC20Transfer(address from, address to, uint256 value, HookData calldata hookData)\n external\n virtual\n returns (bytes4)\n {\n require(checkERC20Transfer(from, to, value, hookData), TransferBlocked());\n return IHook.onERC20Transfer.selector;\n }\n\n /// @inheritdoc IHook\n function onERC20AuthTransfer(\n address, /* sender */\n address, /* from */\n address, /* to */\n uint256, /* value */\n HookData calldata /* hookData */\n ) external pure returns (bytes4) {\n return IHook.onERC20AuthTransfer.selector;\n }\n\n /// @inheritdoc IHook\n function checkERC20Transfer(address from, address to, uint256, /* value */ HookData calldata hookData)\n public\n view\n returns (bool)\n {\n if (uint128(hookData.from).getBit(FREEZE_BIT) == true && !root.endorsed(from) && from != ESCROW_HOOK_ID) {\n // Source is frozen and not endorsed\n return false;\n }\n\n if (root.endorsed(to) || to == address(0) || to == ESCROW_HOOK_ID) {\n // Destination is endorsed or escrow and source was already checked, so the transfer is allowed\n return true;\n }\n\n uint128 toHookData = uint128(hookData.to);\n if (toHookData.getBit(FREEZE_BIT) == true) {\n // Destination is frozen\n return false;\n }\n\n if (toHookData >> 64 < block.timestamp) {\n // Destination is not a member\n return false;\n }\n\n return true;\n }\n\n //----------------------------------------------------------------------------------------------\n // Restriction updates\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHook\n function updateRestriction(address token, bytes memory payload) external auth {\n UpdateRestrictionType updateId = payload.updateRestrictionType();\n\n if (updateId == UpdateRestrictionType.Member) {\n MessageLib.UpdateRestrictionMember memory m = payload.deserializeUpdateRestrictionMember();\n updateMember(token, m.user.toAddress(), m.validUntil);\n } else if (updateId == UpdateRestrictionType.Freeze) {\n MessageLib.UpdateRestrictionFreeze memory m = payload.deserializeUpdateRestrictionFreeze();\n freeze(token, m.user.toAddress());\n } else if (updateId == UpdateRestrictionType.Unfreeze) {\n MessageLib.UpdateRestrictionUnfreeze memory m = payload.deserializeUpdateRestrictionUnfreeze();\n unfreeze(token, m.user.toAddress());\n } else {\n revert InvalidUpdate();\n }\n }\n\n /// @inheritdoc IFreezable\n function freeze(address token, address user) public auth {\n require(user != address(0), CannotFreezeZeroAddress());\n require(!root.endorsed(user), EndorsedUserCannotBeFrozen());\n\n uint128 hookData = uint128(IShareToken(token).hookDataOf(user));\n IShareToken(token).setHookData(user, bytes16(hookData.setBit(FREEZE_BIT, true)));\n\n emit Freeze(token, user);\n }\n\n /// @inheritdoc IFreezable\n function unfreeze(address token, address user) public auth {\n uint128 hookData = uint128(IShareToken(token).hookDataOf(user));\n IShareToken(token).setHookData(user, bytes16(hookData.setBit(FREEZE_BIT, false)));\n\n emit Unfreeze(token, user);\n }\n\n /// @inheritdoc IFreezable\n function isFrozen(address token, address user) public view returns (bool) {\n return uint128(IShareToken(token).hookDataOf(user)).getBit(FREEZE_BIT);\n }\n\n /// @inheritdoc IMemberlist\n function updateMember(address token, address user, uint64 validUntil) public auth {\n require(block.timestamp <= validUntil, InvalidValidUntil());\n require(!root.endorsed(user), EndorsedUserCannotBeUpdated());\n\n uint128 hookData = uint128(validUntil) << 64;\n hookData.setBit(FREEZE_BIT, isFrozen(token, user));\n IShareToken(token).setHookData(user, bytes16(hookData));\n\n emit UpdateMember(token, user, validUntil);\n }\n\n /// @inheritdoc IMemberlist\n function isMember(address token, address user) external view returns (bool isValid, uint64 validUntil) {\n validUntil = abi.encodePacked(IShareToken(token).hookDataOf(user)).toUint64(0);\n isValid = validUntil >= block.timestamp;\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-165\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC165\n function supportsInterface(bytes4 interfaceId) external pure override returns (bool) {\n return interfaceId == type(IHook).interfaceId || interfaceId == type(IERC165).interfaceId;\n }\n}\n" + }, + "src/hooks/RedemptionRestrictions.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\nimport {BitmapLib} from \"src/misc/libraries/BitmapLib.sol\";\nimport {IERC165} from \"src/misc/interfaces/IERC7575.sol\";\n\nimport {IRoot} from \"src/common/interfaces/IRoot.sol\";\nimport {UpdateRestrictionType, MessageLib} from \"src/common/libraries/MessageLib.sol\";\n\nimport {IHook, HookData, ESCROW_HOOK_ID} from \"src/common/interfaces/IHook.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\n\nimport {IFreezable} from \"src/hooks/interfaces/IFreezable.sol\";\nimport {IMemberlist} from \"src/hooks/interfaces/IMemberlist.sol\";\n\n/// @title Redemption Restrictions\n/// @notice Hook implementation that:\n/// * Allows any non-frozen account to receive tokens and transfer tokens\n/// * Requires accounts to be added as a member before submitting a redemption request\n/// * Supports freezing accounts which blocks transfers both to and from them\n/// * Allows authTransferFrom calls\n///\n/// @dev The first 8 bytes (uint64) of hookData is used for the memberlist valid until date,\n/// the last bit is used to denote whether the account is frozen.\ncontract RedemptionRestrictions is Auth, IMemberlist, IFreezable, IHook {\n using BitmapLib for *;\n using MessageLib for *;\n using BytesLib for bytes;\n using CastLib for bytes32;\n\n /// @dev Least significant bit\n uint8 public constant FREEZE_BIT = 0;\n\n IRoot public immutable root;\n\n constructor(address root_, address deployer) Auth(deployer) {\n root = IRoot(root_);\n }\n\n //----------------------------------------------------------------------------------------------\n // Callback from share token\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHook\n function onERC20Transfer(address from, address to, uint256 value, HookData calldata hookData)\n external\n virtual\n returns (bytes4)\n {\n require(checkERC20Transfer(from, to, value, hookData), TransferBlocked());\n return IHook.onERC20Transfer.selector;\n }\n\n /// @inheritdoc IHook\n function onERC20AuthTransfer(\n address, /* sender */\n address, /* from */\n address, /* to */\n uint256, /* value */\n HookData calldata /* hookData */\n ) external pure returns (bytes4) {\n return IHook.onERC20AuthTransfer.selector;\n }\n\n /// @inheritdoc IHook\n function checkERC20Transfer(address from, address to, uint256, /* value */ HookData calldata hookData)\n public\n view\n returns (bool)\n {\n uint128 fromHookData = uint128(hookData.from);\n if (fromHookData.getBit(FREEZE_BIT) == true && !root.endorsed(from)) {\n // Source is frozen and not endorsed\n return false;\n }\n\n uint128 toHookData = uint128(hookData.to);\n if (toHookData.getBit(FREEZE_BIT) == true) {\n // Destination is frozen\n return false;\n }\n\n if (from == address(0) && to == ESCROW_HOOK_ID) {\n // Deposit request fulfillment\n return true;\n }\n\n if (to == ESCROW_HOOK_ID && fromHookData >> 64 < block.timestamp) {\n // Destination is escrow, so it's a redemption request, and the user is not a member\n return false;\n }\n\n return true;\n }\n\n //----------------------------------------------------------------------------------------------\n // Restriction updates\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHook\n function updateRestriction(address token, bytes memory payload) external auth {\n UpdateRestrictionType updateId = payload.updateRestrictionType();\n\n if (updateId == UpdateRestrictionType.Member) {\n MessageLib.UpdateRestrictionMember memory m = payload.deserializeUpdateRestrictionMember();\n updateMember(token, m.user.toAddress(), m.validUntil);\n } else if (updateId == UpdateRestrictionType.Freeze) {\n MessageLib.UpdateRestrictionFreeze memory m = payload.deserializeUpdateRestrictionFreeze();\n freeze(token, m.user.toAddress());\n } else if (updateId == UpdateRestrictionType.Unfreeze) {\n MessageLib.UpdateRestrictionUnfreeze memory m = payload.deserializeUpdateRestrictionUnfreeze();\n unfreeze(token, m.user.toAddress());\n } else {\n revert InvalidUpdate();\n }\n }\n\n /// @inheritdoc IFreezable\n function freeze(address token, address user) public auth {\n require(user != address(0), CannotFreezeZeroAddress());\n require(!root.endorsed(user), EndorsedUserCannotBeFrozen());\n\n uint128 hookData = uint128(IShareToken(token).hookDataOf(user));\n IShareToken(token).setHookData(user, bytes16(hookData.setBit(FREEZE_BIT, true)));\n\n emit Freeze(token, user);\n }\n\n /// @inheritdoc IFreezable\n function unfreeze(address token, address user) public auth {\n uint128 hookData = uint128(IShareToken(token).hookDataOf(user));\n IShareToken(token).setHookData(user, bytes16(hookData.setBit(FREEZE_BIT, false)));\n\n emit Unfreeze(token, user);\n }\n\n /// @inheritdoc IFreezable\n function isFrozen(address token, address user) public view returns (bool) {\n return uint128(IShareToken(token).hookDataOf(user)).getBit(FREEZE_BIT);\n }\n\n /// @inheritdoc IMemberlist\n function updateMember(address token, address user, uint64 validUntil) public auth {\n require(block.timestamp <= validUntil, InvalidValidUntil());\n require(!root.endorsed(user), EndorsedUserCannotBeUpdated());\n\n uint128 hookData = uint128(validUntil) << 64;\n hookData.setBit(FREEZE_BIT, isFrozen(token, user));\n IShareToken(token).setHookData(user, bytes16(hookData));\n\n emit UpdateMember(token, user, validUntil);\n }\n\n /// @inheritdoc IMemberlist\n function isMember(address token, address user) external view returns (bool isValid, uint64 validUntil) {\n validUntil = abi.encodePacked(IShareToken(token).hookDataOf(user)).toUint64(0);\n isValid = validUntil >= block.timestamp;\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-165\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC165\n function supportsInterface(bytes4 interfaceId) external pure override returns (bool) {\n return interfaceId == type(IHook).interfaceId || interfaceId == type(IERC165).interfaceId;\n }\n}\n" + }, + "src/hooks/interfaces/IFreezable.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\ninterface IFreezable {\n // --- Events ---\n event Freeze(address indexed token, address indexed user);\n event Unfreeze(address indexed token, address indexed user);\n\n // --- Errors ---\n error CannotFreezeZeroAddress();\n error EndorsedUserCannotBeFrozen();\n\n // --- Handling freezes ---\n /// @notice Freeze a user balance. Frozen users cannot receive nor send tokens\n function freeze(address token, address user) external;\n\n /// @notice Unfreeze a user balance\n function unfreeze(address token, address user) external;\n\n /// @notice Returns whether the user's tokens are frozen\n function isFrozen(address token, address user) external view returns (bool);\n}\n" + }, + "src/hooks/interfaces/IMemberlist.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\ninterface IMemberlist {\n // --- Events ---\n event UpdateMember(address indexed token, address indexed user, uint64 validUntil);\n\n // --- Errors ---\n error InvalidValidUntil();\n error EndorsedUserCannotBeUpdated();\n\n // --- Managing members ---\n /// @notice Add a member. Non-members cannot receive tokens, but can send tokens to valid members\n /// @param validUntil Timestamp until which the user will be a valid member\n function updateMember(address token, address user, uint64 validUntil) external;\n\n /// @notice Returns whether the user is a valid member of the token\n function isMember(address token, address user) external view returns (bool isValid, uint64 validUntil);\n}\n" + }, + "src/hub/Accounting.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\n\nimport {AccountId} from \"src/common/types/AccountId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {IAccounting, JournalEntry} from \"src/hub/interfaces/IAccounting.sol\";\nimport {TransientStorageLib} from \"src/misc/libraries/TransientStorageLib.sol\";\n\n/// @notice In a transaction there can be multiple journal entries for different pools,\n/// which can be interleaved. We want entries for the same pool to share the same journal ID.\n/// So we're keeping a journal ID per pool in transient storage.\nlibrary TransientJournal {\n function journalId(PoolId poolId) internal view returns (uint256) {\n return TransientStorageLib.tloadUint256(keccak256(abi.encode(\"journalId\", poolId)));\n }\n\n function setJournalId(PoolId poolId, uint256 value) internal {\n TransientStorageLib.tstore(keccak256(abi.encode(\"journalId\", poolId)), value);\n }\n}\n\n/// @title Accounting\n/// @notice Double-entry bookkeeping system.\n/// @dev To add entries, a specific pool needs to be unlocked.\n/// When locking, the debited and credited amounts need to match.\ncontract Accounting is Auth, IAccounting {\n mapping(PoolId => mapping(AccountId => Account)) public accounts;\n\n uint128 public transient debited;\n uint128 public transient credited;\n PoolId internal transient _currentPoolId;\n mapping(PoolId => uint64) internal _poolJournalIdCounter;\n\n constructor(address deployer) Auth(deployer) {}\n\n //----------------------------------------------------------------------------------------------\n // Lock/unlock\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IAccounting\n function unlock(PoolId poolId) external auth {\n require(PoolId.unwrap(_currentPoolId) == 0, AccountingAlreadyUnlocked());\n debited = 0;\n credited = 0;\n _currentPoolId = poolId;\n\n if (TransientJournal.journalId(poolId) == 0) {\n TransientJournal.setJournalId(poolId, _generateJournalId(poolId));\n }\n emit StartJournalId(poolId, TransientJournal.journalId(poolId));\n }\n\n /// @inheritdoc IAccounting\n function lock() external auth {\n require(debited == credited, Unbalanced());\n\n emit EndJournalId(_currentPoolId, TransientJournal.journalId(_currentPoolId));\n _currentPoolId = PoolId.wrap(0);\n }\n\n //----------------------------------------------------------------------------------------------\n // Account creation & metadata\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IAccounting\n function createAccount(PoolId poolId, AccountId account, bool isDebitNormal) external auth {\n require(accounts[poolId][account].lastUpdated == 0, AccountExists());\n accounts[poolId][account] = Account(0, 0, isDebitNormal, uint64(block.timestamp), \"\");\n emit CreateAccount(poolId, account, isDebitNormal);\n }\n\n /// @inheritdoc IAccounting\n function setAccountMetadata(PoolId poolId, AccountId account, bytes calldata metadata) external auth {\n require(accounts[poolId][account].lastUpdated != 0, AccountDoesNotExist());\n accounts[poolId][account].metadata = metadata;\n emit SetAccountMetadata(poolId, account, metadata);\n }\n \n //----------------------------------------------------------------------------------------------\n // Account updates\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IAccounting\n function addDebit(AccountId account, uint128 value) public auth {\n require(!_currentPoolId.isNull(), AccountingLocked());\n\n Account storage acc = accounts[_currentPoolId][account];\n require(acc.lastUpdated != 0, AccountDoesNotExist());\n\n acc.totalDebit += value;\n debited += value;\n acc.lastUpdated = uint64(block.timestamp);\n emit Debit(_currentPoolId, account, value);\n }\n\n /// @inheritdoc IAccounting\n function addCredit(AccountId account, uint128 value) public auth {\n require(!_currentPoolId.isNull(), AccountingLocked());\n\n Account storage acc = accounts[_currentPoolId][account];\n require(acc.lastUpdated != 0, AccountDoesNotExist());\n\n acc.totalCredit += value;\n credited += value;\n acc.lastUpdated = uint64(block.timestamp);\n emit Credit(_currentPoolId, account, value);\n }\n\n /// @inheritdoc IAccounting\n function addJournal(JournalEntry[] memory debits, JournalEntry[] memory credits) external auth {\n for (uint256 i; i < debits.length; i++) {\n addDebit(debits[i].accountId, debits[i].value);\n }\n\n for (uint256 i; i < credits.length; i++) {\n addCredit(credits[i].accountId, credits[i].value);\n }\n }\n\n //----------------------------------------------------------------------------------------------\n // View methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IAccounting\n function accountValue(PoolId poolId, AccountId account) external view returns (bool /* isPositive */, uint128) {\n Account storage acc = accounts[poolId][account];\n require(acc.lastUpdated != 0, AccountDoesNotExist());\n\n if (acc.isDebitNormal) {\n // For debit-normal accounts: Value = Total Debit - Total Credit\n if (acc.totalDebit >= acc.totalCredit) {\n return (true, acc.totalDebit - acc.totalCredit);\n } else {\n return (false, acc.totalCredit - acc.totalDebit);\n }\n } else {\n // For credit-normal accounts: Value = Total Credit - Total Debit\n if (acc.totalCredit >= acc.totalDebit) {\n return (true, acc.totalCredit - acc.totalDebit);\n } else {\n return (false, acc.totalDebit - acc.totalCredit);\n }\n }\n }\n\n /// @inheritdoc IAccounting\n function exists(PoolId poolId, AccountId account) external view returns (bool) {\n return accounts[poolId][account].lastUpdated != 0;\n }\n\n function _generateJournalId(PoolId poolId) internal returns (uint256) {\n return uint256((uint256(poolId.raw()) << 128) | ++_poolJournalIdCounter[poolId]);\n }\n}\n" + }, + "src/hub/Holdings.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IERC7726} from \"src/misc/interfaces/IERC7726.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {d18, D18} from \"src/misc/types/D18.sol\";\n\nimport {PricingLib} from \"src/common/libraries/PricingLib.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {AccountId} from \"src/common/types/AccountId.sol\";\nimport {IHoldings, Holding} from \"src/hub/interfaces/IHoldings.sol\";\nimport {IHubRegistry} from \"src/hub/interfaces/IHubRegistry.sol\";\nimport {IHoldings, Holding, HoldingAccount} from \"src/hub/interfaces/IHoldings.sol\";\n\n/// @title Holdings\n/// @notice Bookkeeping of the holdings and its associated accounting IDs for each pool.\ncontract Holdings is Auth, IHoldings {\n using MathLib for uint256;\n\n IHubRegistry public immutable hubRegistry;\n\n mapping(PoolId => mapping(ShareClassId => mapping(AssetId => Holding))) public holding;\n mapping(PoolId => mapping(ShareClassId => mapping(AssetId => mapping(uint8 kind => AccountId)))) public accountId;\n\n constructor(IHubRegistry hubRegistry_, address deployer) Auth(deployer) {\n hubRegistry = hubRegistry_;\n }\n\n //----------------------------------------------------------------------------------------------\n // Holding creation & updates\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHoldings\n function create(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n IERC7726 valuation_,\n bool isLiability_,\n HoldingAccount[] memory accounts\n ) external auth {\n require(!scId.isNull(), WrongShareClassId());\n require(address(valuation_) != address(0), WrongValuation());\n\n holding[poolId][scId][assetId] = Holding(0, 0, valuation_, isLiability_);\n\n for (uint256 i; i < accounts.length; i++) {\n accountId[poolId][scId][assetId][accounts[i].kind] = accounts[i].accountId;\n }\n\n emit Create(poolId, scId, assetId, valuation_, isLiability_, accounts);\n }\n\n /// @inheritdoc IHoldings\n function setAccountId(PoolId poolId, ShareClassId scId, AssetId assetId, uint8 kind, AccountId accountId_)\n external\n auth\n {\n Holding storage holding_ = holding[poolId][scId][assetId];\n require(address(holding_.valuation) != address(0), HoldingNotFound());\n\n accountId[poolId][scId][assetId][kind] = accountId_;\n\n emit SetAccountId(poolId, scId, assetId, kind, accountId_);\n }\n\n /// @inheritdoc IHoldings\n function updateValuation(PoolId poolId, ShareClassId scId, AssetId assetId, IERC7726 valuation_) external auth {\n require(address(valuation_) != address(0), WrongValuation());\n\n Holding storage holding_ = holding[poolId][scId][assetId];\n require(address(holding_.valuation) != address(0), HoldingNotFound());\n\n holding_.valuation = valuation_;\n\n emit UpdateValuation(poolId, scId, assetId, valuation_);\n }\n\n //----------------------------------------------------------------------------------------------\n // Value updates\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHoldings\n function increase(PoolId poolId, ShareClassId scId, AssetId assetId, D18 pricePoolPerAsset, uint128 amount_)\n external\n auth\n returns (uint128 amountValue)\n {\n Holding storage holding_ = holding[poolId][scId][assetId];\n require(address(holding_.valuation) != address(0), HoldingNotFound());\n\n amountValue = PricingLib.convertWithPrice(\n amount_, hubRegistry.decimals(assetId), hubRegistry.decimals(poolId), pricePoolPerAsset\n ).toUint128();\n\n holding_.assetAmount += amount_;\n holding_.assetAmountValue += amountValue;\n\n emit Increase(poolId, scId, assetId, pricePoolPerAsset, amount_, amountValue);\n }\n\n /// @inheritdoc IHoldings\n function decrease(PoolId poolId, ShareClassId scId, AssetId assetId, D18 pricePoolPerAsset, uint128 amount_)\n external\n auth\n returns (uint128 amountValue)\n {\n Holding storage holding_ = holding[poolId][scId][assetId];\n require(address(holding_.valuation) != address(0), HoldingNotFound());\n\n amountValue = PricingLib.convertWithPrice(\n amount_, hubRegistry.decimals(assetId), hubRegistry.decimals(poolId), pricePoolPerAsset\n ).toUint128();\n\n holding_.assetAmount -= amount_;\n holding_.assetAmountValue -= amountValue;\n\n emit Decrease(poolId, scId, assetId, pricePoolPerAsset, amount_, amountValue);\n }\n\n /// @inheritdoc IHoldings\n function update(PoolId poolId, ShareClassId scId, AssetId assetId)\n external\n auth\n returns (bool isPositive, uint128 diffValue)\n {\n Holding storage holding_ = holding[poolId][scId][assetId];\n require(address(holding_.valuation) != address(0), HoldingNotFound());\n\n uint128 currentAmountValue = holding_.valuation.getQuote(\n holding_.assetAmount, assetId.addr(), hubRegistry.currency(poolId).addr()\n ).toUint128();\n\n isPositive = currentAmountValue >= holding_.assetAmountValue;\n diffValue =\n isPositive ? currentAmountValue - holding_.assetAmountValue : holding_.assetAmountValue - currentAmountValue;\n\n holding_.assetAmountValue = currentAmountValue;\n\n emit Update(poolId, scId, assetId, isPositive, diffValue);\n }\n\n //----------------------------------------------------------------------------------------------\n // View methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHoldings\n function value(PoolId poolId, ShareClassId scId, AssetId assetId) external view returns (uint128 value_) {\n Holding storage holding_ = holding[poolId][scId][assetId];\n require(address(holding_.valuation) != address(0), HoldingNotFound());\n\n return holding_.assetAmountValue;\n }\n\n /// @inheritdoc IHoldings\n function amount(PoolId poolId, ShareClassId scId, AssetId assetId) external view returns (uint128 amount_) {\n Holding storage holding_ = holding[poolId][scId][assetId];\n require(address(holding_.valuation) != address(0), HoldingNotFound());\n\n return holding_.assetAmount;\n }\n\n /// @inheritdoc IHoldings\n function valuation(PoolId poolId, ShareClassId scId, AssetId assetId) external view returns (IERC7726) {\n Holding storage holding_ = holding[poolId][scId][assetId];\n require(address(holding_.valuation) != address(0), HoldingNotFound());\n\n return holding_.valuation;\n }\n\n /// @inheritdoc IHoldings\n function isLiability(PoolId poolId, ShareClassId scId, AssetId assetId) external view returns (bool) {\n Holding storage holding_ = holding[poolId][scId][assetId];\n require(address(holding_.valuation) != address(0), HoldingNotFound());\n\n return holding_.isLiability;\n }\n\n /// @inheritdoc IHoldings\n function exists(PoolId poolId, ShareClassId scId, AssetId assetId) external view returns (bool) {\n return address(holding[poolId][scId][assetId].valuation) != address(0);\n }\n}\n" + }, + "src/hub/Hub.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {D18, d18} from \"src/misc/types/D18.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {IERC7726} from \"src/misc/interfaces/IERC7726.sol\";\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {Multicall, IMulticall} from \"src/misc/Multicall.sol\";\nimport {Recoverable} from \"src/misc/Recoverable.sol\";\n\nimport {IGateway} from \"src/common/interfaces/IGateway.sol\";\nimport {IHubGatewayHandler} from \"src/common/interfaces/IGatewayHandlers.sol\";\nimport {IPoolMessageSender} from \"src/common/interfaces/IGatewaySenders.sol\";\nimport {IHubGuardianActions} from \"src/common/interfaces/IGuardianActions.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {AccountId} from \"src/common/types/AccountId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\n\nimport {IAccounting, JournalEntry} from \"src/hub/interfaces/IAccounting.sol\";\nimport {IHubRegistry} from \"src/hub/interfaces/IHubRegistry.sol\";\nimport {IShareClassManager} from \"src/hub/interfaces/IShareClassManager.sol\";\nimport {IHoldings, HoldingAccount} from \"src/hub/interfaces/IHoldings.sol\";\nimport {IHub, AccountType} from \"src/hub/interfaces/IHub.sol\";\n\n/// @title Hub\n/// @notice Central pool management contract, that brings together all functions in one place.\n/// Pools can assign hub managers which have full rights over all actions.\n///\n/// Also acts as the central contract that routes messages from other chains to the Hub contracts.\ncontract Hub is Multicall, Auth, Recoverable, IHub, IHubGatewayHandler, IHubGuardianActions {\n using MathLib for uint256;\n\n IHubRegistry public immutable hubRegistry;\n\n IGateway public gateway;\n IHoldings public holdings;\n IAccounting public accounting;\n IPoolMessageSender public sender;\n IShareClassManager public shareClassManager;\n\n constructor(\n IShareClassManager shareClassManager_,\n IHubRegistry hubRegistry_,\n IAccounting accounting_,\n IHoldings holdings_,\n IGateway gateway_,\n address deployer\n ) Auth(deployer) {\n shareClassManager = shareClassManager_;\n hubRegistry = hubRegistry_;\n accounting = accounting_;\n holdings = holdings_;\n gateway = gateway_;\n }\n\n //----------------------------------------------------------------------------------------------\n // System methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHub\n function file(bytes32 what, address data) external {\n _auth();\n\n if (what == \"sender\") sender = IPoolMessageSender(data);\n else if (what == \"holdings\") holdings = IHoldings(data);\n else if (what == \"accounting\") accounting = IAccounting(data);\n else if (what == \"shareClassManager\") shareClassManager = IShareClassManager(data);\n else if (what == \"gateway\") gateway = IGateway(data);\n else revert FileUnrecognizedParam();\n\n emit File(what, data);\n }\n\n /// @inheritdoc IMulticall\n /// @notice performs a multicall but all messages sent in the process will be batched\n function multicall(bytes[] calldata data) public payable override {\n bool wasBatching = gateway.isBatching();\n if (!wasBatching) {\n gateway.startBatching();\n gateway.payTransaction{value: msg.value}(msg.sender);\n }\n\n super.multicall(data);\n\n if (!wasBatching) {\n gateway.endBatching();\n }\n }\n\n /// @inheritdoc IHubGuardianActions\n function createPool(PoolId poolId, address admin, AssetId currency) external payable {\n _auth();\n\n require(poolId.centrifugeId() == sender.localCentrifugeId(), InvalidPoolId());\n hubRegistry.registerPool(poolId, admin, currency);\n }\n\n //----------------------------------------------------------------------------------------------\n // Permissionless methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHub\n function notifyDeposit(PoolId poolId, ShareClassId scId, AssetId assetId, bytes32 investor, uint32 maxClaims)\n external\n payable\n {\n _pay();\n\n uint128 totalPayoutShareAmount;\n uint128 totalPaymentAssetAmount;\n uint128 cancelledAssetAmount;\n\n for (uint32 i = 0; i < maxClaims; i++) {\n (uint128 payoutShareAmount, uint128 paymentAssetAmount, uint128 cancelled, bool canClaimAgain) =\n shareClassManager.claimDeposit(poolId, scId, investor, assetId);\n\n totalPayoutShareAmount += payoutShareAmount;\n totalPaymentAssetAmount += paymentAssetAmount;\n\n // Should be written at most once with non-zero amount iff the last claimable epoch was processed and\n // the user had a pending cancellation\n // NOTE: Purposely delaying corresponding message dispatch after deposit fulfillment message\n if (cancelled > 0) {\n cancelledAssetAmount = cancelled;\n }\n\n if (!canClaimAgain) {\n break;\n }\n }\n\n sender.sendFulfilledDepositRequest(\n poolId, scId, assetId, investor, totalPaymentAssetAmount, totalPayoutShareAmount\n );\n\n // If cancellation was queued, notify about delayed cancellation\n if (cancelledAssetAmount > 0) {\n sender.sendFulfilledCancelDepositRequest(poolId, scId, assetId, investor, cancelledAssetAmount);\n }\n }\n\n /// @inheritdoc IHub\n function notifyRedeem(PoolId poolId, ShareClassId scId, AssetId assetId, bytes32 investor, uint32 maxClaims)\n external\n payable\n {\n _pay();\n\n uint128 totalPayoutAssetAmount;\n uint128 totalPaymentShareAmount;\n uint128 cancelledShareAmount;\n\n for (uint32 i = 0; i < maxClaims; i++) {\n (uint128 payoutAssetAmount, uint128 paymentShareAmount, uint128 cancelled, bool canClaimAgain) =\n shareClassManager.claimRedeem(poolId, scId, investor, assetId);\n\n totalPayoutAssetAmount += payoutAssetAmount;\n totalPaymentShareAmount += paymentShareAmount;\n\n // Should be written at most once with non-zero amount iff the last claimable epoch was processed and\n // the user had a pending cancellation\n // NOTE: Purposely delaying corresponding message dispatch after redemption fulfillment message\n if (cancelled > 0) {\n cancelledShareAmount = cancelled;\n }\n\n if (!canClaimAgain) {\n break;\n }\n }\n\n sender.sendFulfilledRedeemRequest(\n poolId, scId, assetId, investor, totalPayoutAssetAmount, totalPaymentShareAmount\n );\n\n // If cancellation was queued, notify about delayed cancellation\n if (cancelledShareAmount > 0) {\n sender.sendFulfilledCancelRedeemRequest(poolId, scId, assetId, investor, cancelledShareAmount);\n }\n }\n\n //----------------------------------------------------------------------------------------------\n // Pool admin methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHub\n function notifyPool(PoolId poolId, uint16 centrifugeId) external payable {\n _isManagerAndPaid(poolId);\n\n emit NotifyPool(centrifugeId, poolId);\n sender.sendNotifyPool(centrifugeId, poolId);\n }\n\n /// @inheritdoc IHub\n function notifyShareClass(PoolId poolId, ShareClassId scId, uint16 centrifugeId, bytes32 hook) external payable {\n _isManagerAndPaid(poolId);\n\n require(shareClassManager.exists(poolId, scId), IShareClassManager.ShareClassNotFound());\n\n (string memory name, string memory symbol, bytes32 salt) = shareClassManager.metadata(scId);\n uint8 decimals = hubRegistry.decimals(poolId);\n\n emit NotifyShareClass(centrifugeId, poolId, scId);\n sender.sendNotifyShareClass(centrifugeId, poolId, scId, name, symbol, decimals, salt, hook);\n }\n\n /// @inheritdoc IHub\n function notifyShareMetadata(PoolId poolId, ShareClassId scId, uint16 centrifugeId) public payable {\n _isManagerAndPaid(poolId);\n\n (string memory name, string memory symbol,) = shareClassManager.metadata(scId);\n\n emit NotifyShareMetadata(centrifugeId, poolId, scId, name, symbol);\n sender.sendNotifyShareMetadata(centrifugeId, poolId, scId, name, symbol);\n }\n\n /// @inheritdoc IHub\n function updateShareHook(PoolId poolId, ShareClassId scId, uint16 centrifugeId, bytes32 hook) public payable {\n _isManagerAndPaid(poolId);\n\n emit UpdateShareHook(centrifugeId, poolId, scId, hook);\n sender.sendUpdateShareHook(centrifugeId, poolId, scId, hook);\n }\n\n /// @inheritdoc IHub\n function notifySharePrice(PoolId poolId, ShareClassId scId, uint16 centrifugeId) public payable {\n _isManagerAndPaid(poolId);\n\n (, D18 poolPerShare) = shareClassManager.metrics(scId);\n\n emit NotifySharePrice(centrifugeId, poolId, scId, poolPerShare);\n sender.sendNotifyPricePoolPerShare(centrifugeId, poolId, scId, poolPerShare);\n }\n\n /// @inheritdoc IHub\n function notifyAssetPrice(PoolId poolId, ShareClassId scId, AssetId assetId) public payable {\n _isManagerAndPaid(poolId);\n D18 pricePoolPerAsset = _pricePoolPerAsset(poolId, scId, assetId);\n emit NotifyAssetPrice(assetId.centrifugeId(), poolId, scId, assetId, pricePoolPerAsset);\n sender.sendNotifyPricePoolPerAsset(poolId, scId, assetId, pricePoolPerAsset);\n }\n\n /// @inheritdoc IHub\n function triggerIssueShares(uint16 centrifugeId, PoolId poolId, ShareClassId scId, address who, uint128 shares)\n public\n payable\n {\n _isManagerAndPaid(poolId);\n\n sender.sendTriggerIssueShares(centrifugeId, poolId, scId, who, shares);\n }\n\n /// @inheritdoc IHub\n function triggerSubmitQueuedShares(uint16 centrifugeId, PoolId poolId, ShareClassId scId) public payable {\n _isManagerAndPaid(poolId);\n\n sender.sendTriggerSubmitQueuedShares(centrifugeId, poolId, scId);\n }\n\n /// @inheritdoc IHub\n function triggerSubmitQueuedAssets(PoolId poolId, ShareClassId scId, AssetId assetId) public payable {\n _isManagerAndPaid(poolId);\n\n sender.sendTriggerSubmitQueuedAssets(poolId, scId, assetId);\n }\n\n /// @inheritdoc IHub\n function setQueue(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bool enabled) public payable {\n _isManagerAndPaid(poolId);\n\n sender.sendSetQueue(centrifugeId, poolId, scId, enabled);\n }\n\n /// @inheritdoc IHub\n function setPoolMetadata(PoolId poolId, bytes calldata metadata) external payable {\n _isManager(poolId);\n\n hubRegistry.setMetadata(poolId, metadata);\n }\n\n /// @inheritdoc IHub\n function updateShareClassMetadata(PoolId poolId, ShareClassId scId, string calldata name, string calldata symbol)\n external\n payable\n {\n _isManager(poolId);\n\n shareClassManager.updateMetadata(poolId, scId, name, symbol);\n }\n\n /// @inheritdoc IHub\n function updateManager(PoolId poolId, address who, bool canManage) external payable {\n _isManager(poolId);\n\n hubRegistry.updateManager(poolId, who, canManage);\n }\n\n /// @inheritdoc IHub\n function addShareClass(PoolId poolId, string calldata name, string calldata symbol, bytes32 salt)\n external\n payable\n returns (ShareClassId scId)\n {\n _isManager(poolId);\n\n return shareClassManager.addShareClass(poolId, name, symbol, salt);\n }\n\n /// @inheritdoc IHub\n function approveDeposits(\n PoolId poolId,\n ShareClassId scId,\n AssetId depositAssetId,\n uint32 nowDepositEpochId,\n uint128 approvedAssetAmount\n ) external payable returns (uint128 pendingAssetAmount, uint128 approvedPoolAmount) {\n _isManagerAndPaid(poolId);\n D18 pricePoolPerAsset = _pricePoolPerAsset(poolId, scId, depositAssetId);\n (pendingAssetAmount, approvedPoolAmount) = shareClassManager.approveDeposits(\n poolId, scId, depositAssetId, nowDepositEpochId, approvedAssetAmount, pricePoolPerAsset\n );\n\n sender.sendApprovedDeposits(poolId, scId, depositAssetId, approvedAssetAmount, pricePoolPerAsset);\n }\n\n /// @inheritdoc IHub\n function approveRedeems(\n PoolId poolId,\n ShareClassId scId,\n AssetId payoutAssetId,\n uint32 nowRedeemEpochId,\n uint128 approvedShareAmount\n ) external payable returns (uint128 pendingShareAmount) {\n _isManager(poolId);\n\n D18 price = _pricePoolPerAsset(poolId, scId, payoutAssetId);\n (pendingShareAmount) =\n shareClassManager.approveRedeems(poolId, scId, payoutAssetId, nowRedeemEpochId, approvedShareAmount, price);\n }\n\n /// @inheritdoc IHub\n function issueShares(\n PoolId poolId,\n ShareClassId scId,\n AssetId depositAssetId,\n uint32 nowIssueEpochId,\n D18 navPoolPerShare\n ) external payable returns (uint128 issuedShareAmount, uint128 depositAssetAmount, uint128 depositPoolAmount) {\n _isManagerAndPaid(poolId);\n\n (issuedShareAmount, depositAssetAmount, depositPoolAmount) =\n shareClassManager.issueShares(poolId, scId, depositAssetId, nowIssueEpochId, navPoolPerShare);\n\n sender.sendIssuedShares(poolId, scId, depositAssetId, issuedShareAmount, navPoolPerShare);\n }\n\n /// @inheritdoc IHub\n function revokeShares(\n PoolId poolId,\n ShareClassId scId,\n AssetId payoutAssetId,\n uint32 nowRevokeEpochId,\n D18 navPoolPerShare\n ) external payable returns (uint128 revokedShareAmount, uint128 payoutAssetAmount, uint128 payoutPoolAmount) {\n _isManagerAndPaid(poolId);\n\n (revokedShareAmount, payoutAssetAmount, payoutPoolAmount) =\n shareClassManager.revokeShares(poolId, scId, payoutAssetId, nowRevokeEpochId, navPoolPerShare);\n\n sender.sendRevokedShares(poolId, scId, payoutAssetId, payoutAssetAmount, revokedShareAmount, navPoolPerShare);\n }\n\n /// @inheritdoc IHub\n function updateRestriction(PoolId poolId, ShareClassId scId, uint16 centrifugeId, bytes calldata payload)\n external\n payable\n {\n _isManagerAndPaid(poolId);\n\n require(shareClassManager.exists(poolId, scId), IShareClassManager.ShareClassNotFound());\n\n emit UpdateRestriction(centrifugeId, poolId, scId, payload);\n sender.sendUpdateRestriction(centrifugeId, poolId, scId, payload);\n }\n\n /// @inheritdoc IHub\n function updateContract(\n PoolId poolId,\n ShareClassId scId,\n uint16 centrifugeId,\n bytes32 target,\n bytes calldata payload\n ) external payable {\n _isManagerAndPaid(poolId);\n\n require(shareClassManager.exists(poolId, scId), IShareClassManager.ShareClassNotFound());\n\n emit UpdateContract(centrifugeId, poolId, scId, target, payload);\n sender.sendUpdateContract(centrifugeId, poolId, scId, target, payload);\n }\n\n /// @inheritdoc IHub\n function updatePricePerShare(PoolId poolId, ShareClassId scId, D18 navPoolPerShare) public payable {\n _isManager(poolId);\n\n shareClassManager.updatePricePerShare(poolId, scId, navPoolPerShare);\n }\n\n /// @inheritdoc IHub\n function createHolding(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n IERC7726 valuation,\n AccountId assetAccount,\n AccountId equityAccount,\n AccountId gainAccount,\n AccountId lossAccount\n ) external payable {\n _isManager(poolId);\n\n require(hubRegistry.isRegistered(assetId), IHubRegistry.AssetNotFound());\n require(\n accounting.exists(poolId, assetAccount) && accounting.exists(poolId, equityAccount)\n && accounting.exists(poolId, lossAccount) && accounting.exists(poolId, gainAccount),\n IAccounting.AccountDoesNotExist()\n );\n\n HoldingAccount[] memory accounts = new HoldingAccount[](4);\n accounts[0] = HoldingAccount(assetAccount, uint8(AccountType.Asset));\n accounts[1] = HoldingAccount(equityAccount, uint8(AccountType.Equity));\n accounts[3] = HoldingAccount(gainAccount, uint8(AccountType.Gain));\n accounts[2] = HoldingAccount(lossAccount, uint8(AccountType.Loss));\n\n holdings.create(poolId, scId, assetId, valuation, false, accounts);\n }\n\n /// @inheritdoc IHub\n function createLiability(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n IERC7726 valuation,\n AccountId expenseAccount,\n AccountId liabilityAccount\n ) external payable {\n _isManager(poolId);\n\n require(hubRegistry.isRegistered(assetId), IHubRegistry.AssetNotFound());\n require(\n accounting.exists(poolId, expenseAccount) && accounting.exists(poolId, liabilityAccount),\n IAccounting.AccountDoesNotExist()\n );\n\n HoldingAccount[] memory accounts = new HoldingAccount[](2);\n accounts[0] = HoldingAccount(expenseAccount, uint8(AccountType.Expense));\n accounts[1] = HoldingAccount(liabilityAccount, uint8(AccountType.Liability));\n\n holdings.create(poolId, scId, assetId, valuation, true, accounts);\n }\n\n /// @inheritdoc IHub\n function updateHoldingValue(PoolId poolId, ShareClassId scId, AssetId assetId) public payable {\n _isManager(poolId);\n\n accounting.unlock(poolId);\n\n (bool isPositive, uint128 diff) = holdings.update(poolId, scId, assetId);\n\n // Save a diff=0 update gas cost\n if (isPositive && diff > 0) {\n if (holdings.isLiability(poolId, scId, assetId)) {\n accounting.addCredit(holdings.accountId(poolId, scId, assetId, uint8(AccountType.Liability)), diff);\n accounting.addDebit(holdings.accountId(poolId, scId, assetId, uint8(AccountType.Expense)), diff);\n } else {\n accounting.addCredit(holdings.accountId(poolId, scId, assetId, uint8(AccountType.Gain)), diff);\n accounting.addDebit(holdings.accountId(poolId, scId, assetId, uint8(AccountType.Asset)), diff);\n }\n } else if (diff > 0) {\n if (holdings.isLiability(poolId, scId, assetId)) {\n accounting.addCredit(holdings.accountId(poolId, scId, assetId, uint8(AccountType.Expense)), diff);\n accounting.addDebit(holdings.accountId(poolId, scId, assetId, uint8(AccountType.Liability)), diff);\n } else {\n accounting.addCredit(holdings.accountId(poolId, scId, assetId, uint8(AccountType.Asset)), diff);\n accounting.addDebit(holdings.accountId(poolId, scId, assetId, uint8(AccountType.Loss)), diff);\n }\n }\n\n accounting.lock();\n }\n\n /// @inheritdoc IHub\n function updateHoldingValuation(PoolId poolId, ShareClassId scId, AssetId assetId, IERC7726 valuation)\n external\n payable\n {\n _isManager(poolId);\n\n holdings.updateValuation(poolId, scId, assetId, valuation);\n }\n\n /// @inheritdoc IHub\n function setHoldingAccountId(PoolId poolId, ShareClassId scId, AssetId assetId, uint8 kind, AccountId accountId)\n external\n payable\n {\n _isManager(poolId);\n\n holdings.setAccountId(poolId, scId, assetId, kind, accountId);\n }\n\n /// @inheritdoc IHub\n function createAccount(PoolId poolId, AccountId account, bool isDebitNormal) public payable {\n _isManager(poolId);\n\n accounting.createAccount(poolId, account, isDebitNormal);\n }\n\n /// @inheritdoc IHub\n function setAccountMetadata(PoolId poolId, AccountId account, bytes calldata metadata) external payable {\n _isManager(poolId);\n\n accounting.setAccountMetadata(poolId, account, metadata);\n }\n\n /// @inheritdoc IHub\n function updateJournal(PoolId poolId, JournalEntry[] memory debits, JournalEntry[] memory credits) external {\n _isManager(poolId);\n\n accounting.unlock(poolId);\n accounting.addJournal(debits, credits);\n accounting.lock();\n }\n\n //----------------------------------------------------------------------------------------------\n // Gateway owner methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHubGatewayHandler\n function registerAsset(AssetId assetId, uint8 decimals) external {\n _auth();\n\n hubRegistry.registerAsset(assetId, decimals);\n }\n\n /// @inheritdoc IHubGatewayHandler\n function depositRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId depositAssetId, uint128 amount)\n external\n {\n _auth();\n\n shareClassManager.requestDeposit(poolId, scId, amount, investor, depositAssetId);\n }\n\n /// @inheritdoc IHubGatewayHandler\n function redeemRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId payoutAssetId, uint128 amount)\n external\n {\n _auth();\n\n shareClassManager.requestRedeem(poolId, scId, amount, investor, payoutAssetId);\n }\n\n /// @inheritdoc IHubGatewayHandler\n function cancelDepositRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId depositAssetId)\n external\n {\n _auth();\n\n uint128 cancelledAssetAmount = shareClassManager.cancelDepositRequest(poolId, scId, investor, depositAssetId);\n\n // Cancellation might have been queued such that it will be executed in the future during claiming\n if (cancelledAssetAmount > 0) {\n sender.sendFulfilledCancelDepositRequest(poolId, scId, depositAssetId, investor, cancelledAssetAmount);\n }\n }\n\n /// @inheritdoc IHubGatewayHandler\n function cancelRedeemRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId payoutAssetId) external {\n _auth();\n\n uint128 cancelledShareAmount = shareClassManager.cancelRedeemRequest(poolId, scId, investor, payoutAssetId);\n\n // Cancellation might have been queued such that it will be executed in the future during claiming\n if (cancelledShareAmount > 0) {\n sender.sendFulfilledCancelRedeemRequest(poolId, scId, payoutAssetId, investor, cancelledShareAmount);\n }\n }\n\n /// @inheritdoc IHubGatewayHandler\n function updateHoldingAmount(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n uint128 amount,\n D18 pricePoolPerAsset,\n bool isIncrease\n ) external {\n _auth();\n\n accounting.unlock(poolId);\n\n bool isLiability = holdings.isLiability(poolId, scId, assetId);\n AccountType debitAccountType = isLiability ? AccountType.Expense : AccountType.Asset;\n AccountType creditAccountType = isLiability ? AccountType.Liability : AccountType.Equity;\n\n if (isIncrease) {\n uint128 value = holdings.increase(poolId, scId, assetId, pricePoolPerAsset, amount);\n accounting.addDebit(holdings.accountId(poolId, scId, assetId, uint8(debitAccountType)), value);\n accounting.addCredit(holdings.accountId(poolId, scId, assetId, uint8(creditAccountType)), value);\n } else {\n uint128 value = holdings.decrease(poolId, scId, assetId, pricePoolPerAsset, amount);\n accounting.addDebit(holdings.accountId(poolId, scId, assetId, uint8(creditAccountType)), value);\n accounting.addCredit(holdings.accountId(poolId, scId, assetId, uint8(debitAccountType)), value);\n }\n\n accounting.lock();\n }\n\n /// @inheritdoc IHubGatewayHandler\n function increaseShareIssuance(PoolId poolId, ShareClassId scId, uint128 amount) external {\n _auth();\n\n shareClassManager.increaseShareClassIssuance(poolId, scId, amount);\n }\n\n /// @inheritdoc IHubGatewayHandler\n function decreaseShareIssuance(PoolId poolId, ShareClassId scId, uint128 amount) external {\n _auth();\n\n shareClassManager.decreaseShareClassIssuance(poolId, scId, amount);\n }\n\n //----------------------------------------------------------------------------------------------\n // Internal methods\n //----------------------------------------------------------------------------------------------\n\n /// @dev Ensure the sender is authorized\n function _auth() internal auth {}\n\n /// @dev Ensure the method can be used without reentrancy issues, and the sender is a pool admin\n function _isManager(PoolId poolId) internal protected {\n require(hubRegistry.manager(poolId, msg.sender), IHub.NotManager());\n }\n\n /// @dev Ensure the sender is authorized\n function _isManagerAndPaid(PoolId poolId) internal {\n _isManager(poolId);\n _pay();\n }\n\n /// @notice Send native tokens to the gateway for transaction payment if it's not in a multicall.\n function _pay() internal {\n if (!gateway.isBatching()) {\n gateway.payTransaction{value: msg.value}(msg.sender);\n }\n }\n\n function _pricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId) internal view returns (D18) {\n AssetId poolCurrency = hubRegistry.currency(poolId);\n // NOTE: We assume symmetric prices are provided by holdings valuation\n IERC7726 valuation = holdings.valuation(poolId, scId, assetId);\n\n // Retrieve amount of 1 asset unit in pool currency\n uint128 assetUnitAmount = (10 ** hubRegistry.decimals(assetId.raw())).toUint128();\n uint128 poolUnitAmount = (10 ** hubRegistry.decimals(poolCurrency.raw())).toUint128();\n uint128 poolAmountPerAsset =\n valuation.getQuote(assetUnitAmount, assetId.addr(), poolCurrency.addr()).toUint128();\n\n // Retrieve price by normalizing by pool denomination\n return d18(poolAmountPerAsset, poolUnitAmount);\n }\n}\n" + }, + "src/hub/HubRegistry.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {IERC6909Decimals} from \"src/misc/interfaces/IERC6909.sol\";\n\nimport {PoolId, newPoolId} from \"src/common/types/PoolId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {IHubRegistry} from \"src/hub/interfaces/IHubRegistry.sol\";\n\n/// @title Hub Registry\n/// @notice Registry of all known pools, currencies, and assets.\ncontract HubRegistry is Auth, IHubRegistry {\n using MathLib for uint256;\n\n mapping(AssetId => uint8) internal _decimals;\n\n mapping(PoolId => bytes) public metadata;\n mapping(PoolId => AssetId) public currency;\n mapping(bytes32 => address) public dependency;\n mapping(PoolId => mapping(address => bool)) public manager;\n\n constructor(address deployer) Auth(deployer) {}\n\n //----------------------------------------------------------------------------------------------\n // Registration methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHubRegistry\n function registerAsset(AssetId assetId, uint8 decimals_) external auth {\n require(_decimals[assetId] == 0, AssetAlreadyRegistered());\n\n _decimals[assetId] = decimals_;\n\n emit NewAsset(assetId, decimals_);\n }\n\n /// @inheritdoc IHubRegistry\n function registerPool(PoolId poolId_, address manager_, AssetId currency_) external auth {\n require(manager_ != address(0), EmptyAccount());\n require(!currency_.isNull(), EmptyCurrency());\n require(currency[poolId_].isNull(), PoolAlreadyRegistered());\n\n manager[poolId_][manager_] = true;\n currency[poolId_] = currency_;\n\n emit NewPool(poolId_, manager_, currency_);\n }\n\n //----------------------------------------------------------------------------------------------\n // Update methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHubRegistry\n function updateManager(PoolId poolId_, address manager_, bool canManage) external auth {\n require(exists(poolId_), NonExistingPool(poolId_));\n require(manager_ != address(0), EmptyAccount());\n\n manager[poolId_][manager_] = canManage;\n\n emit UpdateManager(poolId_, manager_, canManage);\n }\n\n /// @inheritdoc IHubRegistry\n function setMetadata(PoolId poolId_, bytes calldata metadata_) external auth {\n require(exists(poolId_), NonExistingPool(poolId_));\n\n metadata[poolId_] = metadata_;\n\n emit SetMetadata(poolId_, metadata_);\n }\n\n /// @inheritdoc IHubRegistry\n function updateDependency(bytes32 what, address dependency_) external auth {\n dependency[what] = dependency_;\n\n emit UpdateDependency(what, dependency_);\n }\n\n /// @inheritdoc IHubRegistry\n function updateCurrency(PoolId poolId_, AssetId currency_) external auth {\n require(exists(poolId_), NonExistingPool(poolId_));\n require(!currency_.isNull(), EmptyCurrency());\n\n currency[poolId_] = currency_;\n\n emit UpdateCurrency(poolId_, currency_);\n }\n\n //----------------------------------------------------------------------------------------------\n // View methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHubRegistry\n function poolId(uint16 centrifugeId, uint48 postfix) public pure returns (PoolId poolId_) {\n poolId_ = newPoolId(centrifugeId, postfix);\n }\n\n /// @inheritdoc IHubRegistry\n function decimals(AssetId assetId) public view returns (uint8 decimals_) {\n decimals_ = _decimals[assetId];\n require(decimals_ > 0, AssetNotFound());\n }\n\n /// @inheritdoc IHubRegistry\n function decimals(PoolId poolId_) public view returns (uint8 decimals_) {\n decimals_ = _decimals[currency[poolId_]];\n require(decimals_ > 0, AssetNotFound());\n }\n\n /// @inheritdoc IERC6909Decimals\n function decimals(uint256 asset_) external view returns (uint8 decimals_) {\n decimals_ = _decimals[AssetId.wrap(asset_.toUint128())];\n require(decimals_ > 0, AssetNotFound());\n }\n\n /// @inheritdoc IHubRegistry\n function exists(PoolId poolId_) public view returns (bool) {\n return !currency[poolId_].isNull();\n }\n\n /// @inheritdoc IHubRegistry\n function isRegistered(AssetId assetId) public view returns (bool) {\n return _decimals[assetId] != 0;\n }\n}\n" + }, + "src/hub/ShareClassManager.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {D18, d18} from \"src/misc/types/D18.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {ShareClassId, newShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {PricingLib} from \"src/common/libraries/PricingLib.sol\";\n\nimport {IHubRegistry} from \"src/hub/interfaces/IHubRegistry.sol\";\nimport {\n IShareClassManager,\n EpochInvestAmounts,\n EpochRedeemAmounts,\n UserOrder,\n ShareClassMetadata,\n ShareClassMetrics,\n QueuedOrder,\n RequestType,\n EpochId\n} from \"src/hub/interfaces/IShareClassManager.sol\";\n\n/// @title Share Class Manager\n/// @notice Manager for the share classes of a pool, and the core logic for tracking, approving, and fulfilling\n/// requests.\ncontract ShareClassManager is Auth, IShareClassManager {\n using MathLib for *;\n using CastLib for *;\n using BytesLib for bytes;\n\n IHubRegistry public immutable hubRegistry;\n\n // Share classes\n mapping(bytes32 salt => bool) public salts;\n mapping(PoolId poolId => uint32) public shareClassCount;\n mapping(ShareClassId scId => ShareClassMetrics) public metrics;\n mapping(ShareClassId scId => ShareClassMetadata) public metadata;\n mapping(PoolId poolId => mapping(ShareClassId => bool)) public shareClassIds;\n\n // Epochs\n mapping(ShareClassId scId => mapping(AssetId assetId => EpochId)) public epochId;\n mapping(ShareClassId scId => mapping(AssetId assetId => mapping(uint32 epochId_ => EpochInvestAmounts epoch)))\n public epochInvestAmounts;\n mapping(ShareClassId scId => mapping(AssetId assetId => mapping(uint32 epochId_ => EpochRedeemAmounts epoch)))\n public epochRedeemAmounts;\n\n // Pending requests\n mapping(ShareClassId scId => mapping(AssetId payoutAssetId => uint128 pending)) public pendingRedeem;\n mapping(ShareClassId scId => mapping(AssetId depositAssetId => uint128 pending)) public pendingDeposit;\n mapping(ShareClassId scId => mapping(AssetId payoutAssetId => mapping(bytes32 investor => UserOrder pending)))\n public redeemRequest;\n mapping(ShareClassId scId => mapping(AssetId depositAssetId => mapping(bytes32 investor => UserOrder pending)))\n public depositRequest;\n\n // Queued requests\n mapping(ShareClassId scId => mapping(AssetId payoutAssetId => mapping(bytes32 investor => QueuedOrder queued)))\n public queuedRedeemRequest;\n mapping(ShareClassId scId => mapping(AssetId depositAssetId => mapping(bytes32 investor => QueuedOrder queued)))\n public queuedDepositRequest;\n\n constructor(IHubRegistry hubRegistry_, address deployer) Auth(deployer) {\n hubRegistry = hubRegistry_;\n }\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IShareClassManager\n function addShareClass(PoolId poolId, string calldata name, string calldata symbol, bytes32 salt)\n external\n auth\n returns (ShareClassId scId_)\n {\n scId_ = previewNextShareClassId(poolId);\n\n uint32 index = ++shareClassCount[poolId];\n shareClassIds[poolId][scId_] = true;\n\n _updateMetadata(scId_, name, symbol, salt);\n\n emit AddShareClass(poolId, scId_, index, name, symbol, salt);\n }\n\n //----------------------------------------------------------------------------------------------\n // Incoming requests\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IShareClassManager\n function requestDeposit(PoolId poolId, ShareClassId scId_, uint128 amount, bytes32 investor, AssetId depositAssetId)\n external\n auth\n {\n require(exists(poolId, scId_), ShareClassNotFound());\n\n // NOTE: CV ensures amount > 0\n _updatePending(poolId, scId_, amount, true, investor, depositAssetId, RequestType.Deposit);\n }\n\n /// @inheritdoc IShareClassManager\n function cancelDepositRequest(PoolId poolId, ShareClassId scId_, bytes32 investor, AssetId depositAssetId)\n external\n auth\n returns (uint128 cancelledAssetAmount)\n {\n require(exists(poolId, scId_), ShareClassNotFound());\n\n uint128 cancellingAmount = depositRequest[scId_][depositAssetId][investor].pending;\n\n return _updatePending(poolId, scId_, cancellingAmount, false, investor, depositAssetId, RequestType.Deposit);\n }\n\n /// @inheritdoc IShareClassManager\n function requestRedeem(PoolId poolId, ShareClassId scId_, uint128 amount, bytes32 investor, AssetId payoutAssetId)\n external\n auth\n {\n require(exists(poolId, scId_), ShareClassNotFound());\n\n // NOTE: CV ensures amount > 0\n _updatePending(poolId, scId_, amount, true, investor, payoutAssetId, RequestType.Redeem);\n }\n\n /// @inheritdoc IShareClassManager\n function cancelRedeemRequest(PoolId poolId, ShareClassId scId_, bytes32 investor, AssetId payoutAssetId)\n external\n auth\n returns (uint128 cancelledShareAmount)\n {\n require(exists(poolId, scId_), ShareClassNotFound());\n\n uint128 cancellingAmount = redeemRequest[scId_][payoutAssetId][investor].pending;\n\n return _updatePending(poolId, scId_, cancellingAmount, false, investor, payoutAssetId, RequestType.Redeem);\n }\n\n //----------------------------------------------------------------------------------------------\n // Manager actions\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IShareClassManager\n function approveDeposits(\n PoolId poolId,\n ShareClassId scId_,\n AssetId depositAssetId,\n uint32 nowDepositEpochId,\n uint128 approvedAssetAmount,\n D18 pricePoolPerAsset\n ) external auth returns (uint128 pendingAssetAmount, uint128 approvedPoolAmount) {\n require(exists(poolId, scId_), ShareClassNotFound());\n require(\n nowDepositEpochId == nowDepositEpoch(scId_, depositAssetId),\n EpochNotInSequence(nowDepositEpochId, nowDepositEpoch(scId_, depositAssetId))\n );\n\n // Limit in case approved > pending due to race condition of FM approval and async incoming requests\n pendingAssetAmount = pendingDeposit[scId_][depositAssetId];\n require(approvedAssetAmount <= pendingAssetAmount, InsufficientPending());\n require(approvedAssetAmount > 0, ZeroApprovalAmount());\n\n approvedPoolAmount = PricingLib.convertWithPrice(\n approvedAssetAmount, hubRegistry.decimals(depositAssetId), hubRegistry.decimals(poolId), pricePoolPerAsset\n ).toUint128();\n\n // Update epoch data\n EpochInvestAmounts storage epochAmounts = epochInvestAmounts[scId_][depositAssetId][nowDepositEpochId];\n epochAmounts.approvedAssetAmount = approvedAssetAmount;\n epochAmounts.approvedPoolAmount = approvedPoolAmount;\n epochAmounts.pendingAssetAmount = pendingAssetAmount;\n epochAmounts.pricePoolPerAsset = pricePoolPerAsset;\n\n // Reduce pending\n pendingDeposit[scId_][depositAssetId] -= approvedAssetAmount;\n pendingAssetAmount -= approvedAssetAmount;\n\n epochId[scId_][depositAssetId].deposit = nowDepositEpochId;\n emit ApproveDeposits(\n poolId,\n scId_,\n depositAssetId,\n nowDepositEpochId,\n approvedPoolAmount,\n approvedAssetAmount,\n pendingAssetAmount\n );\n }\n\n /// @inheritdoc IShareClassManager\n function approveRedeems(\n PoolId poolId,\n ShareClassId scId_,\n AssetId payoutAssetId,\n uint32 nowRedeemEpochId,\n uint128 approvedShareAmount,\n D18 pricePoolPerAsset\n ) external auth returns (uint128 pendingShareAmount) {\n require(exists(poolId, scId_), ShareClassNotFound());\n require(\n nowRedeemEpochId == nowRedeemEpoch(scId_, payoutAssetId),\n EpochNotInSequence(nowRedeemEpochId, nowRedeemEpoch(scId_, payoutAssetId))\n );\n\n // Limit in case approved > pending due to race condition of FM approval and async incoming requests\n pendingShareAmount = pendingRedeem[scId_][payoutAssetId];\n require(approvedShareAmount <= pendingShareAmount, InsufficientPending());\n require(approvedShareAmount > 0, ZeroApprovalAmount());\n\n // Update epoch data\n EpochRedeemAmounts storage epochAmounts = epochRedeemAmounts[scId_][payoutAssetId][nowRedeemEpochId];\n epochAmounts.approvedShareAmount = approvedShareAmount;\n epochAmounts.pendingShareAmount = pendingShareAmount;\n epochAmounts.pricePoolPerAsset = pricePoolPerAsset;\n\n // Reduce pending\n pendingRedeem[scId_][payoutAssetId] -= approvedShareAmount;\n pendingShareAmount -= approvedShareAmount;\n epochId[scId_][payoutAssetId].redeem = nowRedeemEpochId;\n emit ApproveRedeems(poolId, scId_, payoutAssetId, nowRedeemEpochId, approvedShareAmount, pendingShareAmount);\n }\n\n /// @inheritdoc IShareClassManager\n function issueShares(\n PoolId poolId,\n ShareClassId scId_,\n AssetId depositAssetId,\n uint32 nowIssueEpochId,\n D18 navPoolPerShare\n ) external auth returns (uint128 issuedShareAmount, uint128 depositAssetAmount, uint128 depositPoolAmount) {\n require(exists(poolId, scId_), ShareClassNotFound());\n require(nowIssueEpochId <= epochId[scId_][depositAssetId].deposit, EpochNotFound());\n require(\n nowIssueEpochId == nowIssueEpoch(scId_, depositAssetId),\n EpochNotInSequence(nowIssueEpochId, nowIssueEpoch(scId_, depositAssetId))\n );\n\n EpochInvestAmounts storage epochAmounts = epochInvestAmounts[scId_][depositAssetId][nowIssueEpochId];\n epochAmounts.navPoolPerShare = navPoolPerShare;\n\n issuedShareAmount = PricingLib.assetToShareAmount(\n epochAmounts.approvedAssetAmount,\n hubRegistry.decimals(depositAssetId),\n hubRegistry.decimals(poolId),\n epochAmounts.pricePoolPerAsset,\n navPoolPerShare,\n MathLib.Rounding.Down\n ).toUint128();\n\n metrics[scId_].totalIssuance += issuedShareAmount;\n epochAmounts.issuedAt = block.timestamp.toUint64();\n epochId[scId_][depositAssetId].issue = nowIssueEpochId;\n\n depositAssetAmount = epochAmounts.approvedAssetAmount;\n depositPoolAmount = epochAmounts.approvedPoolAmount;\n\n emit IssueShares(\n poolId,\n scId_,\n depositAssetId,\n nowIssueEpochId,\n navPoolPerShare,\n PricingLib.priceAssetPerShare(epochAmounts.navPoolPerShare, epochAmounts.pricePoolPerAsset),\n issuedShareAmount\n );\n }\n\n /// @inheritdoc IShareClassManager\n function revokeShares(\n PoolId poolId,\n ShareClassId scId_,\n AssetId payoutAssetId,\n uint32 nowRevokeEpochId,\n D18 navPoolPerShare\n ) external auth returns (uint128 revokedShareAmount, uint128 payoutAssetAmount, uint128 payoutPoolAmount) {\n require(exists(poolId, scId_), ShareClassNotFound());\n require(nowRevokeEpochId <= epochId[scId_][payoutAssetId].redeem, EpochNotFound());\n require(\n nowRevokeEpochId == nowRevokeEpoch(scId_, payoutAssetId),\n EpochNotInSequence(nowRevokeEpochId, nowRevokeEpoch(scId_, payoutAssetId))\n );\n\n EpochRedeemAmounts storage epochAmounts = epochRedeemAmounts[scId_][payoutAssetId][nowRevokeEpochId];\n epochAmounts.navPoolPerShare = navPoolPerShare;\n\n require(epochAmounts.approvedShareAmount <= metrics[scId_].totalIssuance, RevokeMoreThanIssued());\n\n // NOTE: shares and pool currency have the same decimals - no conversion needed!\n payoutPoolAmount = navPoolPerShare.mulUint128(epochAmounts.approvedShareAmount, MathLib.Rounding.Down);\n\n payoutAssetAmount = PricingLib.poolToAssetAmount(\n payoutPoolAmount,\n hubRegistry.decimals(poolId),\n hubRegistry.decimals(payoutAssetId),\n epochAmounts.pricePoolPerAsset,\n MathLib.Rounding.Down\n ).toUint128();\n revokedShareAmount = epochAmounts.approvedShareAmount;\n\n metrics[scId_].totalIssuance -= epochAmounts.approvedShareAmount;\n epochAmounts.payoutAssetAmount = payoutAssetAmount;\n epochAmounts.revokedAt = block.timestamp.toUint64();\n epochId[scId_][payoutAssetId].revoke = nowRevokeEpochId;\n\n emit RevokeShares(\n poolId,\n scId_,\n payoutAssetId,\n nowRevokeEpochId,\n navPoolPerShare,\n PricingLib.priceAssetPerShare(epochAmounts.navPoolPerShare, epochAmounts.pricePoolPerAsset),\n epochAmounts.approvedShareAmount,\n payoutAssetAmount,\n payoutPoolAmount\n );\n }\n\n /// @inheritdoc IShareClassManager\n function updatePricePerShare(PoolId poolId, ShareClassId scId_, D18 navPoolPerShare) external auth {\n require(exists(poolId, scId_), ShareClassNotFound());\n\n ShareClassMetrics storage m = metrics[scId_];\n m.navPerShare = navPoolPerShare;\n emit UpdateShareClass(poolId, scId_, navPoolPerShare);\n }\n\n /// @inheritdoc IShareClassManager\n function updateMetadata(PoolId poolId, ShareClassId scId_, string calldata name, string calldata symbol)\n external\n auth\n {\n require(exists(poolId, scId_), ShareClassNotFound());\n\n _updateMetadata(scId_, name, symbol, bytes32(0));\n\n emit UpdateMetadata(poolId, scId_, name, symbol);\n }\n\n /// @inheritdoc IShareClassManager\n function increaseShareClassIssuance(PoolId poolId, ShareClassId scId_, uint128 amount) external auth {\n require(exists(poolId, scId_), ShareClassNotFound());\n\n uint128 newIssuance = metrics[scId_].totalIssuance + amount;\n metrics[scId_].totalIssuance = newIssuance;\n\n emit RemoteIssueShares(poolId, scId_, amount);\n }\n\n /// @inheritdoc IShareClassManager\n function decreaseShareClassIssuance(PoolId poolId, ShareClassId scId_, uint128 amount) external auth {\n require(exists(poolId, scId_), ShareClassNotFound());\n require(metrics[scId_].totalIssuance >= amount, DecreaseMoreThanIssued());\n\n uint128 newIssuance = metrics[scId_].totalIssuance - amount;\n metrics[scId_].totalIssuance = newIssuance;\n\n emit RemoteRevokeShares(poolId, scId_, amount);\n }\n\n //----------------------------------------------------------------------------------------------\n // Claiming methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IShareClassManager\n function claimDeposit(PoolId poolId, ShareClassId scId_, bytes32 investor, AssetId depositAssetId)\n public\n auth\n returns (\n uint128 payoutShareAmount,\n uint128 paymentAssetAmount,\n uint128 cancelledAssetAmount,\n bool canClaimAgain\n )\n {\n require(exists(poolId, scId_), ShareClassNotFound());\n\n UserOrder storage userOrder = depositRequest[scId_][depositAssetId][investor];\n require(userOrder.pending > 0, NoOrderFound());\n require(userOrder.lastUpdate <= epochId[scId_][depositAssetId].issue, IssuanceRequired());\n canClaimAgain = userOrder.lastUpdate < epochId[scId_][depositAssetId].issue;\n EpochInvestAmounts storage epochAmounts = epochInvestAmounts[scId_][depositAssetId][userOrder.lastUpdate];\n\n paymentAssetAmount = epochAmounts.approvedAssetAmount == 0\n ? 0\n : userOrder.pending.mulDiv(epochAmounts.approvedAssetAmount, epochAmounts.pendingAssetAmount).toUint128();\n\n // NOTE: Due to precision loss, the sum of claimable user amounts is leq than the amount of minted share class\n // tokens corresponding to the approved share amount (instead of equality). I.e., it is possible for an epoch to\n // have an excess of a share class tokens which cannot be claimed by anyone.\n // This excess is at most n-1 share tokens for an epoch with n claimable users.\n if (paymentAssetAmount > 0) {\n uint256 paymentPoolAmount = PricingLib.convertWithPrice(\n paymentAssetAmount,\n hubRegistry.decimals(depositAssetId),\n hubRegistry.decimals(poolId),\n epochAmounts.pricePoolPerAsset\n );\n payoutShareAmount =\n epochAmounts.navPoolPerShare.reciprocalMulUint256(paymentPoolAmount, MathLib.Rounding.Down).toUint128();\n\n userOrder.pending -= paymentAssetAmount;\n }\n\n emit ClaimDeposit(\n poolId,\n scId_,\n userOrder.lastUpdate,\n investor,\n depositAssetId,\n paymentAssetAmount,\n userOrder.pending,\n payoutShareAmount,\n epochAmounts.issuedAt\n );\n\n // If there is nothing to claim anymore we can short circuit to the latest epoch\n if (userOrder.pending == 0) {\n // The current epoch is always one step ahead of the stored one\n userOrder.lastUpdate = nowDepositEpoch(scId_, depositAssetId);\n canClaimAgain = false;\n } else {\n userOrder.lastUpdate += 1;\n }\n\n // If user claimed up to latest approval epoch, move queued to pending\n if (userOrder.lastUpdate == nowDepositEpoch(scId_, depositAssetId)) {\n cancelledAssetAmount =\n _postClaimUpdateQueued(poolId, scId_, investor, depositAssetId, userOrder, RequestType.Deposit);\n }\n }\n\n /// @inheritdoc IShareClassManager\n function claimRedeem(PoolId poolId, ShareClassId scId_, bytes32 investor, AssetId payoutAssetId)\n public\n auth\n returns (\n uint128 payoutAssetAmount,\n uint128 paymentShareAmount,\n uint128 cancelledShareAmount,\n bool canClaimAgain\n )\n {\n require(exists(poolId, scId_), ShareClassNotFound());\n\n UserOrder storage userOrder = redeemRequest[scId_][payoutAssetId][investor];\n require(userOrder.pending > 0, NoOrderFound());\n require(userOrder.lastUpdate <= epochId[scId_][payoutAssetId].revoke, RevocationRequired());\n canClaimAgain = userOrder.lastUpdate < epochId[scId_][payoutAssetId].revoke;\n\n EpochRedeemAmounts storage epochAmounts = epochRedeemAmounts[scId_][payoutAssetId][userOrder.lastUpdate];\n\n paymentShareAmount = epochAmounts.approvedShareAmount == 0\n ? 0\n : userOrder.pending.mulDiv(epochAmounts.approvedShareAmount, epochAmounts.pendingShareAmount).toUint128();\n\n // NOTE: Due to precision loss, the sum of claimable user amounts is leq than the amount of minted share class\n // tokens corresponding to the approved share amount (instead of equality). I.e., it is possible for an epoch to\n // have an excess of a share class tokens which cannot be claimed by anyone.\n // This excess is at most n-1 share tokens for an epoch with n claimable users.\n if (paymentShareAmount > 0) {\n payoutAssetAmount = PricingLib.shareToAssetAmount(\n paymentShareAmount,\n hubRegistry.decimals(poolId),\n hubRegistry.decimals(payoutAssetId),\n epochAmounts.pricePoolPerAsset,\n epochAmounts.navPoolPerShare,\n MathLib.Rounding.Down\n ).toUint128();\n\n userOrder.pending -= paymentShareAmount;\n }\n\n emit ClaimRedeem(\n poolId,\n scId_,\n userOrder.lastUpdate,\n investor,\n payoutAssetId,\n paymentShareAmount,\n userOrder.pending,\n payoutAssetAmount,\n epochAmounts.revokedAt\n );\n\n // If there is nothing to claim anymore we can short circuit the in between epochs\n if (userOrder.pending == 0) {\n // The current epoch is always one step ahead of the stored one\n userOrder.lastUpdate = nowRedeemEpoch(scId_, payoutAssetId);\n canClaimAgain = false;\n } else {\n userOrder.lastUpdate += 1;\n }\n\n if (userOrder.lastUpdate == nowRedeemEpoch(scId_, payoutAssetId)) {\n cancelledShareAmount =\n _postClaimUpdateQueued(poolId, scId_, investor, payoutAssetId, userOrder, RequestType.Redeem);\n }\n }\n\n //----------------------------------------------------------------------------------------------\n // View methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IShareClassManager\n function previewNextShareClassId(PoolId poolId) public view returns (ShareClassId scId) {\n return newShareClassId(poolId, shareClassCount[poolId] + 1);\n }\n\n /// @inheritdoc IShareClassManager\n function previewShareClassId(PoolId poolId, uint32 index) public pure returns (ShareClassId scId) {\n return newShareClassId(poolId, index);\n }\n\n /// @inheritdoc IShareClassManager\n function exists(PoolId poolId, ShareClassId scId_) public view returns (bool) {\n return shareClassIds[poolId][scId_];\n }\n\n /// @inheritdoc IShareClassManager\n function nowDepositEpoch(ShareClassId scId_, AssetId depositAssetId) public view returns (uint32) {\n return epochId[scId_][depositAssetId].deposit + 1;\n }\n\n /// @inheritdoc IShareClassManager\n function nowIssueEpoch(ShareClassId scId_, AssetId depositAssetId) public view returns (uint32) {\n return epochId[scId_][depositAssetId].issue + 1;\n }\n\n /// @inheritdoc IShareClassManager\n function nowRedeemEpoch(ShareClassId scId_, AssetId depositAssetId) public view returns (uint32) {\n return epochId[scId_][depositAssetId].redeem + 1;\n }\n\n /// @inheritdoc IShareClassManager\n function nowRevokeEpoch(ShareClassId scId_, AssetId depositAssetId) public view returns (uint32) {\n return epochId[scId_][depositAssetId].revoke + 1;\n }\n\n /// @inheritdoc IShareClassManager\n function maxDepositClaims(ShareClassId scId_, bytes32 investor, AssetId depositAssetId)\n public\n view\n returns (uint32)\n {\n return _maxClaims(depositRequest[scId_][depositAssetId][investor], epochId[scId_][depositAssetId].deposit);\n }\n\n /// @inheritdoc IShareClassManager\n function maxRedeemClaims(ShareClassId scId_, bytes32 investor, AssetId payoutAssetId)\n public\n view\n returns (uint32)\n {\n return _maxClaims(redeemRequest[scId_][payoutAssetId][investor], epochId[scId_][payoutAssetId].redeem);\n }\n\n function _maxClaims(UserOrder memory userOrder, uint32 lastEpoch) private pure returns (uint32) {\n // User order either not set or not processed\n if (userOrder.pending == 0 || userOrder.lastUpdate > lastEpoch) {\n return 0;\n }\n\n return lastEpoch - userOrder.lastUpdate + 1;\n }\n\n //----------------------------------------------------------------------------------------------\n // Internal methods\n //----------------------------------------------------------------------------------------------\n\n function _updateMetadata(ShareClassId scId_, string calldata name, string calldata symbol, bytes32 salt) private {\n uint256 nameLen = bytes(name).length;\n require(nameLen > 0 && nameLen <= 128, InvalidMetadataName());\n\n uint256 symbolLen = bytes(symbol).length;\n require(symbolLen > 0 && symbolLen <= 32, InvalidMetadataSymbol());\n\n ShareClassMetadata storage meta = metadata[scId_];\n\n // Ensure that the salt is not being updated or is being set for the first time\n require(\n (salt == bytes32(0) && meta.salt != bytes32(0)) || (salt != bytes32(0) && meta.salt == bytes32(0)),\n InvalidSalt()\n );\n\n if (salt != bytes32(0) && meta.salt == bytes32(0)) {\n require(!salts[salt], AlreadyUsedSalt());\n salts[salt] = true;\n meta.salt = salt;\n }\n\n meta.name = name;\n meta.symbol = symbol;\n }\n\n function _postClaimUpdateQueued(\n PoolId poolId,\n ShareClassId scId_,\n bytes32 investor,\n AssetId assetId,\n UserOrder storage userOrder,\n RequestType requestType\n ) private returns (uint128 cancelledAmount) {\n QueuedOrder storage queued = requestType == RequestType.Deposit\n ? queuedDepositRequest[scId_][assetId][investor]\n : queuedRedeemRequest[scId_][assetId][investor];\n\n // Increment pending by queued or cancel everything\n uint128 updatePendingAmount = queued.isCancelling ? userOrder.pending : queued.amount;\n if (queued.isCancelling) {\n cancelledAmount = userOrder.pending + queued.amount;\n userOrder.pending = 0;\n } else {\n userOrder.pending += queued.amount;\n }\n\n if (requestType == RequestType.Deposit) {\n _updatePendingDeposit(\n poolId,\n scId_,\n updatePendingAmount,\n !queued.isCancelling,\n investor,\n assetId,\n userOrder,\n QueuedOrder(false, 0)\n );\n } else {\n _updatePendingRedeem(\n poolId,\n scId_,\n updatePendingAmount,\n !queued.isCancelling,\n investor,\n assetId,\n userOrder,\n QueuedOrder(false, 0)\n );\n }\n\n // Clear queued\n queued.isCancelling = false;\n queued.amount = 0;\n }\n\n /// @notice Updates the amount of a deposit or redeem request.\n ///\n /// @param poolId Identifier of the pool\n /// @param scId_ Identifier of the share class\n /// @param amount Amount which is updated\n /// @param isIncrement Whether the amount is positive (additional request) or negative (cancellation)\n /// @param investor Address of the entity which is depositing\n /// @param assetId Identifier of the asset which the investor either used as deposit or wants to redeem to\n /// @param requestType Flag indicating whether the request is a deposit or redeem request\n /// @return cancelledAmount Pending amount which was cancelled\n function _updatePending(\n PoolId poolId,\n ShareClassId scId_,\n uint128 amount,\n bool isIncrement,\n bytes32 investor,\n AssetId assetId,\n RequestType requestType\n ) private returns (uint128 cancelledAmount) {\n UserOrder storage userOrder = requestType == RequestType.Deposit\n ? depositRequest[scId_][assetId][investor]\n : redeemRequest[scId_][assetId][investor];\n QueuedOrder storage queued = requestType == RequestType.Deposit\n ? queuedDepositRequest[scId_][assetId][investor]\n : queuedRedeemRequest[scId_][assetId][investor];\n\n // We must only update either queued or pending\n if (_updateQueued(poolId, scId_, amount, isIncrement, investor, assetId, userOrder, queued, requestType)) {\n return 0;\n }\n\n cancelledAmount = isIncrement ? 0 : amount;\n // NOTE: If we decrease the pending, we decrease usually by the full amount\n // We keep subtraction of amount over setting to zero on purpose to not limit future higher level logic\n userOrder.pending = isIncrement ? userOrder.pending + amount : userOrder.pending - amount;\n\n userOrder.lastUpdate =\n requestType == RequestType.Deposit ? nowDepositEpoch(scId_, assetId) : nowRedeemEpoch(scId_, assetId);\n\n if (requestType == RequestType.Deposit) {\n _updatePendingDeposit(poolId, scId_, amount, isIncrement, investor, assetId, userOrder, queued);\n } else {\n _updatePendingRedeem(poolId, scId_, amount, isIncrement, investor, assetId, userOrder, queued);\n }\n }\n\n /// @notice Checks whether the pending amount can be updated. If not, it updates the queued amount.\n ///\n /// @param poolId Identifier of the pool\n /// @param scId_ Identifier of the share class\n /// @param amount Amount which is updated\n /// @param isIncrement Whether the amount is positive (additional request) or negative (cancellation)\n /// @param investor Address of the entity which is depositing\n /// @param assetId Identifier of the asset which the investor either used as deposit or wants to redeem to\n /// @param userOrder User order storage for the deposit or redeem request\n /// @param requestType Flag indicating whether the request is a deposit or redeem request\n /// @return skipPendingUpdate Flag indicating whether the pending amount can be updated which is true if the user\n /// does not need to claim\n function _updateQueued(\n PoolId poolId,\n ShareClassId scId_,\n uint128 amount,\n bool isIncrement,\n bytes32 investor,\n AssetId assetId,\n UserOrder storage userOrder,\n QueuedOrder storage queued,\n RequestType requestType\n ) private returns (bool skipPendingUpdate) {\n uint32 lastEpoch =\n requestType == RequestType.Deposit ? epochId[scId_][assetId].deposit : epochId[scId_][assetId].redeem;\n uint32 currentEpoch = lastEpoch + 1;\n\n // Short circuit if user can mutate pending, i.e. last update happened after latest approval or is first update\n if (userOrder.lastUpdate == currentEpoch || userOrder.pending == 0 || lastEpoch == 0) {\n return false;\n }\n\n // Block increasing queued amount if cancelling is already queued\n // NOTE: Can only happen due to race condition as CV blocks requests if cancellation is in progress\n require(!(queued.isCancelling && amount > 0), CancellationQueued());\n\n if (!isIncrement) {\n queued.isCancelling = true;\n } else {\n queued.amount += amount;\n }\n\n if (requestType == RequestType.Deposit) {\n uint128 pendingTotal = pendingDeposit[scId_][assetId];\n emit UpdateDepositRequest(\n poolId,\n scId_,\n assetId,\n currentEpoch,\n investor,\n userOrder.pending,\n pendingTotal,\n queued.amount,\n queued.isCancelling\n );\n } else {\n uint128 pendingTotal = pendingRedeem[scId_][assetId];\n\n emit UpdateRedeemRequest(\n poolId,\n scId_,\n assetId,\n currentEpoch,\n investor,\n userOrder.pending,\n pendingTotal,\n queued.amount,\n queued.isCancelling\n );\n }\n\n return true;\n }\n\n function _updatePendingDeposit(\n PoolId poolId,\n ShareClassId scId_,\n uint128 amount,\n bool isIncrement,\n bytes32 investor,\n AssetId assetId,\n UserOrder storage userOrder,\n QueuedOrder memory queued\n ) private {\n uint128 pendingTotal = pendingDeposit[scId_][assetId];\n pendingTotal = isIncrement ? pendingTotal + amount : pendingTotal - amount;\n pendingDeposit[scId_][assetId] = pendingTotal;\n\n emit UpdateDepositRequest(\n poolId,\n scId_,\n assetId,\n nowDepositEpoch(scId_, assetId),\n investor,\n userOrder.pending,\n pendingTotal,\n queued.amount,\n queued.isCancelling\n );\n }\n\n function _updatePendingRedeem(\n PoolId poolId,\n ShareClassId scId_,\n uint128 amount,\n bool isIncrement,\n bytes32 investor,\n AssetId assetId,\n UserOrder storage userOrder,\n QueuedOrder memory queued\n ) private {\n uint128 pendingTotal = pendingRedeem[scId_][assetId];\n pendingTotal = isIncrement ? pendingTotal + amount : pendingTotal - amount;\n pendingRedeem[scId_][assetId] = pendingTotal;\n\n emit UpdateRedeemRequest(\n poolId,\n scId_,\n assetId,\n nowRedeemEpoch(scId_, assetId),\n investor,\n userOrder.pending,\n pendingTotal,\n queued.amount,\n queued.isCancelling\n );\n }\n}\n" + }, + "src/hub/interfaces/IAccounting.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {AccountId} from \"src/common/types/AccountId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\n\nstruct JournalEntry {\n uint128 value;\n AccountId accountId;\n}\n\ninterface IAccounting {\n /// @notice Emitted when a an entry is done\n event Credit(PoolId indexed poolId, AccountId indexed account, uint128 value);\n event Debit(PoolId indexed poolId, AccountId indexed account, uint128 value);\n\n /// @notice Emitted at the beginning and end of a journal entry\n event StartJournalId(PoolId indexed poolId, uint256 journalId);\n event EndJournalId(PoolId indexed poolId, uint256 journalId);\n\n /// @notice Emitted when a new account is created\n event CreateAccount(PoolId indexed poolId, AccountId indexed account, bool isDebitNormal);\n\n /// @notice Emitted when metadata is set for an account\n event SetAccountMetadata(PoolId indexed poolId, AccountId indexed account, bytes metadata);\n\n /// @notice Dispatched when the pool is already unlocked.\n error AccountingAlreadyUnlocked();\n\n /// @notice Dispatched when the pool is not unlocked to interact with.\n error AccountingLocked();\n\n /// @notice Dispatched when the debit and credit side do not match at the end of a transaction.\n error Unbalanced();\n\n /// @notice Dispatched when trying to create an account that already exists.\n error AccountExists();\n\n /// @notice Dispatched when trying debit or credit an account that doesn't exists.\n error AccountDoesNotExist();\n\n /// @notice Represents an account\n struct Account {\n uint128 totalDebit;\n uint128 totalCredit;\n bool isDebitNormal;\n uint64 lastUpdated;\n bytes metadata;\n }\n\n /// @notice Debits an account. Increase the value of debit-normal accounts, decrease for credit-normal ones.\n /// @param account The account to debit\n /// @param value Amount being debited\n function addDebit(AccountId account, uint128 value) external;\n\n /// @notice Credits an account. Decrease the value of debit-normal accounts, increase for credit-normal ones.\n /// @param account The account to credit\n /// @param value Amount being credited\n function addCredit(AccountId account, uint128 value) external;\n\n /// @notice Apply addDebit and addCredit to each journal entry\n function addJournal(JournalEntry[] memory debits, JournalEntry[] memory credits) external;\n\n /// @notice Unlocks a pool for journal entries\n /// @param poolId The pool to unlock\n function unlock(PoolId poolId) external;\n\n /// @notice Closes the transaction and checks if the entries are balanced.\n function lock() external;\n\n /// @notice Creates an account.\n /// @param poolId The pool the account belongs to\n /// @param account The account to create\n /// @param isDebitNormal Whether the account is debit-normal or credit-normal\n function createAccount(PoolId poolId, AccountId account, bool isDebitNormal) external;\n\n /// @notice Sets metadata associated to an existent account.\n /// @param poolId The pool the account belongs to\n /// @param account The account to set metadata for\n /// @param metadata The metadata to set\n function setAccountMetadata(PoolId poolId, AccountId account, bytes calldata metadata) external;\n\n /// @notice Returns the value of an account\n /// @param poolId The pool the account belongs to\n /// @param account The account to get the value of\n /// @return isPositive Indicates whether value is a positive or negative value\n /// @return value The value of the account\n function accountValue(PoolId poolId, AccountId account) external view returns (bool isPositive, uint128 value);\n\n /// @notice Returns whether an account exists\n /// @param poolId The pool the account belongs to\n /// @param account The account to check\n /// @return True if the account exists, false otherwise\n function exists(PoolId poolId, AccountId account) external view returns (bool);\n}\n" + }, + "src/hub/interfaces/IHoldings.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IERC7726} from \"src/misc/interfaces/IERC7726.sol\";\nimport {D18} from \"src/misc/types/D18.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {AccountId} from \"src/common/types/AccountId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nstruct Holding {\n uint128 assetAmount;\n uint128 assetAmountValue;\n IERC7726 valuation; // Used for existence\n bool isLiability;\n}\n\nstruct HoldingAccount {\n AccountId accountId;\n uint8 kind;\n}\n\ninterface IHoldings {\n /// @notice Emitted when a holding is created\n event Create(\n PoolId indexed,\n ShareClassId indexed scId,\n AssetId indexed assetId,\n IERC7726 valuation,\n bool isLiability,\n HoldingAccount[] accounts\n );\n\n /// @notice Emitted when a holding is increased\n event Increase(\n PoolId indexed,\n ShareClassId indexed scId,\n AssetId indexed assetId,\n D18 pricePoolPerAsset,\n uint128 amount,\n uint128 increasedValue\n );\n\n /// @notice Emitted when a holding is decreased\n event Decrease(\n PoolId indexed,\n ShareClassId indexed scId,\n AssetId indexed assetId,\n D18 pricePoolPerAsset,\n uint128 amount,\n uint128 decreasedValue\n );\n\n /// @notice Emitted when the holding is updated\n event Update(\n PoolId indexed, ShareClassId indexed scId, AssetId indexed assetId, bool isPositive, uint128 diffValue\n );\n\n /// @notice Emitted when a holding valuation is updated\n event UpdateValuation(PoolId indexed, ShareClassId indexed scId, AssetId indexed assetId, IERC7726 valuation);\n\n /// @notice Emitted when an account is for a holding is set\n event SetAccountId(\n PoolId indexed, ShareClassId indexed scId, AssetId indexed assetId, uint8 kind, AccountId accountId\n );\n\n /// @notice Item was not found for a required action\n error HoldingNotFound();\n\n /// @notice Valuation is not valid.\n error WrongValuation();\n\n /// @notice ShareClassId is not valid.\n error WrongShareClassId();\n\n /// @notice AssetId is not valid.\n error WrongAssetId();\n\n /// @notice Creates a new holding in a pool using a valuation\n function create(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n IERC7726 valuation,\n bool isLiability,\n HoldingAccount[] memory accounts\n ) external;\n\n /// @notice Increments the amount of a holding and updates the value for that increment.\n /// @return value The value the holding has increment.\n function increase(PoolId poolId, ShareClassId scId, AssetId assetId, D18 pricePoolPerAsset, uint128 amount)\n external\n returns (uint128 value);\n\n /// @notice Decrements the amount of a holding and updates the value for that decrement.\n /// @return value The value the holding has decrement.\n function decrease(PoolId poolId, ShareClassId scId, AssetId assetId, D18 pricePoolPerAsset, uint128 amount)\n external\n returns (uint128 value);\n\n /// @notice Reset the value of a holding using the current valuation.\n /// @return isPositive Indicates whether the diffValue is positive or negative\n /// @return diffValue The difference in value after the new valuation.\n function update(PoolId poolId, ShareClassId scId, AssetId assetId)\n external\n returns (bool isPositive, uint128 diffValue);\n\n /// @notice Updates the valuation method used for this holding.\n function updateValuation(PoolId poolId, ShareClassId scId, AssetId assetId, IERC7726 valuation) external;\n\n /// @notice Sets an account id for an specific kind\n function setAccountId(PoolId poolId, ShareClassId scId, AssetId assetId, uint8 kind, AccountId accountId)\n external;\n\n /// @notice Returns the value of this holding.\n function value(PoolId poolId, ShareClassId scId, AssetId assetId) external view returns (uint128 value);\n\n /// @notice Returns the amount of this holding.\n function amount(PoolId poolId, ShareClassId scId, AssetId assetId) external view returns (uint128 amount);\n\n /// @notice Returns the valuation method used for this holding.\n function valuation(PoolId poolId, ShareClassId scId, AssetId assetId) external view returns (IERC7726);\n\n /// @notice Returns if the holding is a liability\n function isLiability(PoolId poolId, ShareClassId scId, AssetId assetId) external view returns (bool);\n\n /// @notice Returns an account id for an specific kind\n function accountId(PoolId poolId, ShareClassId scId, AssetId assetId, uint8 kind)\n external\n view\n returns (AccountId);\n\n /// @notice Tells if the holding exists for an asset in a share class\n function exists(PoolId poolId, ShareClassId scId, AssetId assetId) external view returns (bool);\n}\n" + }, + "src/hub/interfaces/IHub.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {D18} from \"src/misc/types/D18.sol\";\nimport {IERC7726} from \"src/misc/interfaces/IERC7726.sol\";\n\nimport {VaultUpdateKind} from \"src/common/libraries/MessageLib.sol\";\nimport {IGateway} from \"src/common/interfaces/IGateway.sol\";\nimport {IPoolMessageSender} from \"src/common/interfaces/IGatewaySenders.sol\";\n\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {AccountId} from \"src/common/types/AccountId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {IShareClassManager} from \"src/hub/interfaces/IShareClassManager.sol\";\nimport {IAccounting, JournalEntry} from \"src/hub/interfaces/IAccounting.sol\";\nimport {IHubRegistry} from \"src/hub/interfaces/IHubRegistry.sol\";\nimport {IHoldings} from \"src/hub/interfaces/IHoldings.sol\";\n\n/// @notice Account types used by Hub\nenum AccountType {\n /// @notice Debit normal account for tracking assets\n Asset,\n /// @notice Credit normal account for tracking equities\n Equity,\n /// @notice Credit normal account for tracking losses\n Loss,\n /// @notice Credit normal account for tracking profits\n Gain,\n /// @notice Debit normal account for tracking expenses\n Expense,\n /// @notice Credit normal account for tracking liabilities\n Liability\n}\n\n/// @notice Interface with all methods available in the system used by actors\ninterface IHub {\n event NotifyPool(uint16 indexed centrifugeId, PoolId indexed poolId);\n event NotifyShareClass(uint16 indexed centrifugeId, PoolId indexed poolId, ShareClassId scId);\n event NotifyShareMetadata(\n uint16 indexed centrifugeId, PoolId indexed poolId, ShareClassId scId, string name, string symbol\n );\n event UpdateShareHook(uint16 indexed centrifugeId, PoolId indexed poolId, ShareClassId scId, bytes32 hook);\n event NotifySharePrice(uint16 indexed centrifugeId, PoolId indexed poolId, ShareClassId scId, D18 poolPerShare);\n event NotifyAssetPrice(\n uint16 indexed centrifugeId, PoolId indexed poolId, ShareClassId scId, AssetId assetId, D18 pricePoolPerAsset\n );\n event UpdateRestriction(uint16 indexed centrifugeId, PoolId indexed poolId, ShareClassId scId, bytes payload);\n event UpdateContract(\n uint16 indexed centrifugeId, PoolId indexed poolId, ShareClassId scId, bytes32 target, bytes payload\n );\n\n /// @notice Emitted when a call to `file()` was performed.\n event File(bytes32 what, address addr);\n\n /// @notice Dispatched when the `what` parameter of `file()` is not supported by the implementation.\n error FileUnrecognizedParam();\n\n /// @notice Dispatched when the pool is already unlocked.\n /// It means when calling to `execute()` inside `execute()`.\n error PoolAlreadyUnlocked();\n\n /// @notice Dispatched when the pool can not be unlocked by the caller\n error NotManager();\n\n /// @notice Dispatched when an invalid centrifuge ID is set in the pool ID.\n error InvalidPoolId();\n\n function gateway() external view returns (IGateway);\n function holdings() external view returns (IHoldings);\n function accounting() external view returns (IAccounting);\n function hubRegistry() external view returns (IHubRegistry);\n function sender() external view returns (IPoolMessageSender);\n function shareClassManager() external view returns (IShareClassManager);\n\n /// @notice Updates a contract parameter.\n /// @param what Name of the parameter to update.\n /// Accepts a `bytes32` representation of 'hubRegistry', 'assetRegistry', 'accounting', 'holdings', 'gateway' and '\n /// sender' as string value.\n function file(bytes32 what, address data) external;\n\n /// @notice Notify a deposit for an investor address located in the chain where the asset belongs\n function notifyDeposit(PoolId poolId, ShareClassId scId, AssetId depositAssetId, bytes32 investor, uint32 maxClaims)\n external\n payable;\n\n /// @notice Notify a redemption for an investor address located in the chain where the asset belongs\n function notifyRedeem(PoolId poolId, ShareClassId scId, AssetId payoutAssetId, bytes32 investor, uint32 maxClaims)\n external\n payable;\n\n /// @notice Notify to a CV instance that a new pool is available\n /// @param centrifugeId Chain where CV instance lives\n function notifyPool(PoolId poolId, uint16 centrifugeId) external payable;\n\n /// @notice Notify to a CV instance that a new share class is available\n /// @param centrifugeId Chain where CV instance lives\n /// @param hook The hook address of the share class\n function notifyShareClass(PoolId poolId, ShareClassId scId, uint16 centrifugeId, bytes32 hook) external payable;\n\n /// @notice Notify to a CV instance that share metadata has updated\n function notifyShareMetadata(PoolId poolId, ShareClassId scId, uint16 centrifugeId) external payable;\n\n /// @notice Update on a CV instance the hook of a share token\n function updateShareHook(PoolId poolId, ShareClassId scId, uint16 centrifugeId, bytes32 hook) external payable;\n\n /// @notice Notify to a CV instance the latest available price in POOL_UNIT / SHARE_UNIT\n /// @dev The receiving centrifugeId is derived from the provided assetId\n /// @param centrifugeId Chain to where the share price is notified\n /// @param scId Identifier of the share class\n function notifySharePrice(PoolId poolId, ShareClassId scId, uint16 centrifugeId) external payable;\n\n /// @notice Notify to a CV instance the latest available price in POOL_UNIT / ASSET_UNIT\n /// @dev The receiving centrifugeId is derived from the provided assetId\n /// @param scId Identifier of the share class\n /// @param assetId Identifier of the asset\n function notifyAssetPrice(PoolId poolId, ShareClassId scId, AssetId assetId) external payable;\n\n /// @notice Attach custom data to a pool\n function setPoolMetadata(PoolId poolId, bytes calldata metadata) external payable;\n\n /// @notice Update name & symbol of share class\n function updateShareClassMetadata(PoolId poolId, ShareClassId scId, string calldata name, string calldata symbol)\n external\n payable;\n\n /// @notice Allow/disallow an account to interact as pool manager\n function updateManager(PoolId poolId, address who, bool canManage) external payable;\n\n /// @notice Add a new share class to the pool\n function addShareClass(PoolId poolId, string calldata name, string calldata symbol, bytes32 salt)\n external\n payable\n returns (ShareClassId scId);\n\n /// @notice Approves an asset amount of all deposit requests for the given triplet of pool id, share class id and\n /// deposit asset id.\n /// @param scId Identifier of the share class\n /// @param depositAssetId Identifier of the asset locked for the deposit request\n /// @param nowDepositEpochId The epoch for which deposits will be approved.\n /// @param approvedAssetAmount Ampunt of assets that will be approved\n function approveDeposits(\n PoolId poolId,\n ShareClassId scId,\n AssetId depositAssetId,\n uint32 nowDepositEpochId,\n uint128 approvedAssetAmount\n ) external payable returns (uint128 pendingAssetAmount, uint128 approvedPoolAmount);\n\n /// @notice Approves a percentage of all redemption requests for the given triplet of pool id, share class id and\n /// deposit asset id.\n /// @param scId Identifier of the share class\n /// @param payoutAssetId Identifier of the asset for which all requests want to exchange their share class tokens\n /// @param nowRedeemEpochId The epoch for which redemptions will be approved.\n /// @param approvedShareAmount Amount of shares that will be approved\n function approveRedeems(\n PoolId poolId,\n ShareClassId scId,\n AssetId payoutAssetId,\n uint32 nowRedeemEpochId,\n uint128 approvedShareAmount\n ) external payable returns (uint128 pendingShareAmount);\n\n /// @notice Emits new shares for the given identifier based on the provided NAV per share.\n /// @param depositAssetId Identifier of the deposit asset for which shares should be issued\n /// @param nowIssueEpochId The epoch for which shares will be issued.\n /// @param navPoolPerShare Total value of assets of the share class per share\n function issueShares(\n PoolId poolId,\n ShareClassId id,\n AssetId depositAssetId,\n uint32 nowIssueEpochId,\n D18 navPoolPerShare\n ) external payable returns (uint128 issuedShareAmount, uint128 depositAssetAmount, uint128 depositPoolAmount);\n\n /// @notice Take back shares for the given identifier based on the provided NAV per share.\n /// deposit asset id.\n /// @param payoutAssetId Identifier of the asset for which all requests want to exchange their share class tokens\n /// @param nowRevokeEpochId The epoch for which shares will be issued.\n /// @param navPoolPerShare Total value of assets of the share class per share\n function revokeShares(\n PoolId poolId,\n ShareClassId scId,\n AssetId payoutAssetId,\n uint32 nowRevokeEpochId,\n D18 navPoolPerShare\n ) external payable returns (uint128 revokedShareAmount, uint128 payoutAssetAmount, uint128 payoutPoolAmount);\n\n /// @notice Tells the BalanceSheet to issue/revoke shares.\n function triggerIssueShares(uint16 centrifugeId, PoolId poolId, ShareClassId scId, address who, uint128 shares)\n external\n payable;\n\n /// @notice Tell the BalanceSheet to send a message back with the queued issued/revoked shares.\n function triggerSubmitQueuedShares(uint16 centrifugeId, PoolId poolId, ShareClassId scId) external payable;\n\n /// @notice Tell the BalanceSheet to send a message back with the queued deposits/withdrawals.\n /// @param assetId Identifier of the asset which has queued deposits/withdrawals\n function triggerSubmitQueuedAssets(PoolId poolId, ShareClassId scId, AssetId assetId) external payable;\n\n /// @notice Tell the BalanceSheet to enable or disable the shares queue.\n function setQueue(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bool enabled) external payable;\n\n /// @notice Update remotely a restriction.\n /// @param centrifugeId Chain where CV instance lives.\n /// @param payload content of the restriction update to execute.\n function updateRestriction(PoolId poolId, ShareClassId scId, uint16 centrifugeId, bytes calldata payload)\n external\n payable;\n\n /// @notice Update remotely an existing vault.\n /// @param centrifugeId Chain where CV instance lives.\n /// @param target contract where to execute in CV. Check IUpdateContract interface.\n /// @param payload content of the update to execute.\n function updateContract(\n PoolId poolId,\n ShareClassId scId,\n uint16 centrifugeId,\n bytes32 target,\n bytes calldata payload\n ) external payable;\n\n /// @notice Update the price per share of a share class\n /// @param scId The share class identifier\n /// @param pricePoolPerShare The new price per share\n function updatePricePerShare(PoolId poolId, ShareClassId scId, D18 pricePoolPerShare) external payable;\n\n /// @notice Create a new holding associated to the asset in a share class.\n /// It will register the different accounts used for holdings.\n /// The accounts have to be created beforehand.\n /// The same account can be used for different kinds.\n /// e.g.: The equity, gain, and loss account can be the same account.\n /// They can also be shared across assets.\n /// e.g.: All assets can use the same equity account.\n /// @param valuation Used to transform between payment assets and pool currency\n /// @param assetAccount Used to track the asset value\n /// @param equityAccount Used to track the equity value\n /// @param gainAccount Used to track the gain value\n /// @param lossAccount Used to track the loss value\n function createHolding(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n IERC7726 valuation,\n AccountId assetAccount,\n AccountId equityAccount,\n AccountId gainAccount,\n AccountId lossAccount\n ) external payable;\n\n /// @notice Create a new liablity associated to the asset in a share class.\n /// It will register the different accounts used for holdings.\n /// The accounts have to be created beforehand.\n /// @param valuation Used to transform between the holding asset and pool currency\n /// @param expenseAccount Used to track the expense value\n /// @param liabilityAccount Used to track the liability value\n function createLiability(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n IERC7726 valuation,\n AccountId expenseAccount,\n AccountId liabilityAccount\n ) external payable;\n\n /// @notice Updates the pool currency value of this holding based of the associated valuation.\n function updateHoldingValue(PoolId poolId, ShareClassId scId, AssetId assetId) external payable;\n\n /// @notice Updates the valuation used by a holding\n /// @param valuation Used to transform between the holding asset and pool currency\n function updateHoldingValuation(PoolId poolId, ShareClassId scId, AssetId assetId, IERC7726 valuation)\n external\n payable;\n\n /// @notice Set an account of a holding\n function setHoldingAccountId(PoolId poolId, ShareClassId scId, AssetId assetId, uint8 kind, AccountId accountId)\n external\n payable;\n\n /// @notice Creates an account\n /// @param accountId Then new AccountId used\n /// @param isDebitNormal Determines if the account should be used as debit-normal or credit-normal\n function createAccount(PoolId poolId, AccountId accountId, bool isDebitNormal) external payable;\n\n /// @notice Attach custom data to an account\n function setAccountMetadata(PoolId poolId, AccountId account, bytes calldata metadata) external payable;\n\n /// @notice Perform an accounting entries update.\n function updateJournal(PoolId poolId, JournalEntry[] memory debits, JournalEntry[] memory credits) external;\n}\n" + }, + "src/hub/interfaces/IHubRegistry.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IERC6909Decimals} from \"src/misc/interfaces/IERC6909.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {IShareClassManager} from \"src/hub/interfaces/IShareClassManager.sol\";\n\ninterface IHubRegistry is IERC6909Decimals {\n event NewAsset(AssetId indexed assetId, uint8 decimals);\n event NewPool(PoolId poolId, address indexed manager, AssetId indexed currency);\n event UpdateManager(PoolId indexed poolId, address indexed manager, bool canManage);\n event SetMetadata(PoolId indexed poolId, bytes metadata);\n event UpdateDependency(bytes32 indexed what, address dependency);\n event UpdateCurrency(PoolId indexed poolId, AssetId currency);\n\n error NonExistingPool(PoolId id);\n error AssetAlreadyRegistered();\n error PoolAlreadyRegistered();\n error EmptyAccount();\n error EmptyCurrency();\n error EmptyShareClassManager();\n error AssetNotFound();\n\n /// @notice Register a new asset.\n function registerAsset(AssetId assetId, uint8 decimals_) external;\n\n /// @notice Register a new pool.\n function registerPool(PoolId poolId, address manager, AssetId currency) external;\n\n /// @notice allow/disallow an address as a manager for the pool\n function updateManager(PoolId poolId, address newManager, bool canManage) external;\n\n /// @notice sets metadata for this pool\n function setMetadata(PoolId poolId, bytes calldata metadata) external;\n\n /// @notice updates a dependency of the system\n function updateDependency(bytes32 what, address dependency) external;\n\n /// @notice updates the currency of the pool\n function updateCurrency(PoolId poolId, AssetId currency) external;\n\n /// @notice returns the metadata attached to the pool, if any.\n function metadata(PoolId poolId) external view returns (bytes memory);\n\n /// @notice returns the currency of the pool\n function currency(PoolId poolId) external view returns (AssetId);\n\n /// @notice returns the dependency used in the system\n function dependency(bytes32 what) external view returns (address);\n\n /// @notice returns whether the account is a manager\n function manager(PoolId poolId, address who) external view returns (bool);\n\n /// @notice compute a pool ID given an ID postfix\n function poolId(uint16 centrifugeId, uint48 postfix) external view returns (PoolId poolId);\n\n /// @notice returns the decimals for an asset\n function decimals(AssetId assetId) external view returns (uint8);\n\n /// @notice returns the decimals for a pool\n function decimals(PoolId poolId) external view returns (uint8);\n\n /// @notice checks the existence of a pool\n function exists(PoolId poolId) external view returns (bool);\n\n /// @notice checks the existence of an asset\n function isRegistered(AssetId assetId) external view returns (bool);\n}\n" + }, + "src/hub/interfaces/IShareClassManager.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {D18} from \"src/misc/types/D18.sol\";\nimport {IERC7726} from \"src/misc/interfaces/IERC7726.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nstruct EpochRedeemAmounts {\n /// @dev Amount of shares pending to be redeemed at time of epoch\n uint128 pendingShareAmount;\n /// @dev Total approved amount of redeemed share class tokens\n uint128 approvedShareAmount;\n /// @dev Total asset amount of revoked share class tokens\n uint128 payoutAssetAmount;\n /// @dev The amount of pool currency per unit of asset at time of approval\n D18 pricePoolPerAsset;\n /// @dev The amount of pool currency per unit of share at time of revocation\n D18 navPoolPerShare;\n /// @dev block timestamp when shares of epoch were revoked\n uint64 revokedAt;\n}\n\nstruct EpochInvestAmounts {\n /// @dev Total pending asset amount of deposit asset at time of epoch\n uint128 pendingAssetAmount;\n /// @dev Total approved asset amount of deposit asset\n uint128 approvedAssetAmount;\n /// @dev Total approved pool amount of deposit asset\n uint128 approvedPoolAmount;\n /// @dev The amount of pool currency per unit of asset at time of approval\n D18 pricePoolPerAsset;\n /// @dev The amount of pool currency per unit of share at time of issuance\n D18 navPoolPerShare;\n /// @dev block timestamp when shares of epoch were issued\n uint64 issuedAt;\n}\n\nstruct UserOrder {\n /// @dev Pending amount in deposit asset denomination\n uint128 pending;\n /// @dev Index of epoch in which last order was made\n uint32 lastUpdate;\n}\n\nstruct ShareClassMetadata {\n /// @dev The name of the share class token\n string name;\n /// @dev The symbol of the share class token\n string symbol;\n /// @dev The salt of the share class token\n bytes32 salt;\n}\n\nstruct ShareClassMetrics {\n /// @dev Total number of shares\n uint128 totalIssuance;\n /// @dev The latest net asset value per share class token\n D18 navPerShare;\n}\n\nstruct QueuedOrder {\n /// @dev Whether the user requested a cancellation which is now queued\n bool isCancelling;\n /// @dev The queued increased request amount\n uint128 amount;\n}\n\nenum RequestType {\n /// @dev Whether the request is a deposit one\n Deposit,\n /// @dev Whether the request is a redeem one\n Redeem\n}\n\nstruct EpochId {\n uint32 deposit;\n uint32 redeem;\n uint32 issue;\n uint32 revoke;\n}\n\ninterface IShareClassManager {\n /// Events\n event AddShareClass(\n PoolId indexed poolId, ShareClassId indexed scId, uint32 indexed index, string name, string symbol, bytes32 salt\n );\n event UpdateMetadata(PoolId indexed poolId, ShareClassId indexed scId, string name, string symbol);\n event ApproveDeposits(\n PoolId indexed poolId,\n ShareClassId indexed scId,\n AssetId indexed depositAssetId,\n uint32 epoch,\n uint128 approvedPoolAmount,\n uint128 approvedAssetAmount,\n uint128 pendingAssetAmount\n );\n event ApproveRedeems(\n PoolId indexed poolId,\n ShareClassId indexed scId,\n AssetId indexed payoutAssetId,\n uint32 epoch,\n uint128 approvedShareAmount,\n uint128 pendingShareAmount\n );\n event IssueShares(\n PoolId indexed poolId,\n ShareClassId indexed scId,\n AssetId indexed depositAssetId,\n uint32 epoch,\n D18 navPoolPerShare,\n D18 navAssetPerShare,\n uint128 issuedShareAmount\n );\n event RemoteIssueShares(PoolId indexed poolId, ShareClassId indexed scId, uint128 issuedShareAmount);\n event RevokeShares(\n PoolId indexed poolId,\n ShareClassId indexed scId,\n AssetId indexed payoutAssetId,\n uint32 epoch,\n D18 navPoolPerShare,\n D18 navAssetPerShare,\n uint128 revokedShareAmount,\n uint128 revokedAssetAmount,\n uint128 revokedPoolAmount\n );\n event RemoteRevokeShares(PoolId indexed poolId, ShareClassId indexed scId, uint128 revokedAssetAmount);\n event ClaimDeposit(\n PoolId indexed poolId,\n ShareClassId indexed scId,\n uint32 epoch,\n bytes32 investor,\n AssetId indexed depositAssetId,\n uint128 paymentAssetAmount,\n uint128 pendingAssetAmount,\n uint128 claimedShareAmount,\n uint64 issuedAt\n );\n event ClaimRedeem(\n PoolId indexed poolId,\n ShareClassId indexed scId,\n uint32 epoch,\n bytes32 investor,\n AssetId indexed payoutAssetId,\n uint128 paymentShareAmount,\n uint128 pendingShareAmount,\n uint128 claimedAssetAmount,\n uint64 revokedAt\n );\n event AddShareClass(PoolId indexed poolId, ShareClassId indexed scId, uint32 indexed index);\n event UpdateShareClass(PoolId indexed poolId, ShareClassId indexed scId, D18 navPoolPerShare);\n event UpdateDepositRequest(\n PoolId indexed poolId,\n ShareClassId indexed scId,\n AssetId indexed depositAssetId,\n uint32 epoch,\n bytes32 investor,\n uint128 pendingUserAssetAmount,\n uint128 pendingTotalAssetAmount,\n uint128 queuedUserAssetAmount,\n bool pendingCancellation\n );\n event UpdateRedeemRequest(\n PoolId indexed poolId,\n ShareClassId indexed scId,\n AssetId indexed payoutAssetId,\n uint32 epoch,\n bytes32 investor,\n uint128 pendingUserShareAmount,\n uint128 pendingTotalShareAmount,\n uint128 queuedUserShareAmount,\n bool pendingCancellation\n );\n\n /// Errors\n error EpochNotInSequence(uint32 providedEpoch, uint32 nowEpoch);\n error NoOrderFound();\n error InsufficientPending();\n error ApprovalRequired();\n error IssuanceRequired();\n error AlreadyIssued();\n error RevocationRequired();\n error ZeroApprovalAmount();\n error InvalidMetadataSize();\n error InvalidMetadataName();\n error InvalidMetadataSymbol();\n error InvalidSalt();\n error AlreadyUsedSalt();\n error RevokeMoreThanIssued();\n error PoolMissing();\n error ShareClassNotFound();\n error EpochNotFound();\n error DecreaseMoreThanIssued();\n error CancellationQueued();\n\n /// Functions\n\n /// @notice Creates or updates a request to deposit (exchange) an asset amount for share class tokens.\n ///\n /// @param poolId Identifier of the pool\n /// @param scId Identifier of the share class\n /// @param amount Asset token amount which is deposited\n /// @param investor Centrifuge Vault address of the entity which is depositing\n /// @param depositAssetId Identifier of the asset which the investor used for their deposit request\n function requestDeposit(PoolId poolId, ShareClassId scId, uint128 amount, bytes32 investor, AssetId depositAssetId)\n external;\n\n /// @notice Cancels a pending deposit request.\n ///\n /// @param poolId Identifier of the pool\n /// @param scId Identifier of the share class\n /// @param investor Centrifuge Vault address of the entity which is cancelling\n /// @param depositAssetId Identifier of the asset which the investor used for their deposit request\n /// @return cancelledAssetAmount The deposit amount which was previously pending and is now cancelled. This amount\n /// was not potentially (partially) swapped to the pool amount in case the deposit asset cannot be exchanged 1:1\n /// into the pool token\n function cancelDepositRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId depositAssetId)\n external\n returns (uint128 cancelledAssetAmount);\n\n /// @notice Creates or updates a request to redeem (exchange) share class tokens for some asset.\n ///\n /// @param poolId Identifier of the pool\n /// @param scId Identifier of the share class\n /// @param amount Share class token amount which should be redeemed\n /// @param investor Centrifuge Vault address of the entity which is redeeming\n /// @param payoutAssetId Identifier of the asset which the investor eventually receives back for their redeemed\n /// share class tokens\n function requestRedeem(PoolId poolId, ShareClassId scId, uint128 amount, bytes32 investor, AssetId payoutAssetId)\n external;\n\n /// @notice Cancels a pending redeem request.\n ///\n /// @param poolId Identifier of the pool\n /// @param scId Identifier of the share class\n /// @param investor Centrifuge Vault address of the entity which is cancelling\n /// @param payoutAssetId Identifier of the asset which the investor eventually receives back for their redeemed\n /// share class tokens\n /// @return cancelledShareAmount The redeem amount which was previously pending and is now cancelled\n function cancelRedeemRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId payoutAssetId)\n external\n returns (uint128 cancelledShareAmount);\n\n /// @notice Approves an asset amount of all deposit requests for the given triplet of pool id, share class id and\n /// deposit asset id.\n /// @dev nowDepositEpochId MUST be called sequentially.\n ///\n /// @param poolId Identifier of the pool\n /// @param scId Identifier of the share class\n /// @param depositAssetId Identifier of the asset locked for the deposit request\n /// @param nowDepositEpochId The epoch for which shares will be approved.\n /// @param approvedAssetAmount Amount of assets that will be approved for deposit\n /// @param pricePoolPerAsset Amount of pool unit one gets for a unit of asset\n /// @return pendingAssetAmount Amount of assets still pending for deposit\n /// @return approvedPoolAmount Amount of pool units approved for deposit\n function approveDeposits(\n PoolId poolId,\n ShareClassId scId,\n AssetId depositAssetId,\n uint32 nowDepositEpochId,\n uint128 approvedAssetAmount,\n D18 pricePoolPerAsset\n ) external returns (uint128 pendingAssetAmount, uint128 approvedPoolAmount);\n\n /// @notice Approves a share class token amount of all redeem requests for the given triplet of pool id, share class\n /// id and payout asset id.\n /// @dev nowRedeemEpochId MUST be called sequentially.\n ///\n /// @param poolId Identifier of the pool\n /// @param scId Identifier of the share class\n /// @param payoutAssetId Identifier of the asset for which all requests want to exchange their share class tokens\n /// for\n /// @param nowRedeemEpochId The epoch for which shares will be approved.\n /// @param approvedShareAmount Amount of shares that will be approved for redemption\n /// @param pricePoolPerAsset Amount of pool unit one gets for a unit of asset\n /// @return pendingShareAmount Sum of redemption request amounts in share class token amount which was not approved\n function approveRedeems(\n PoolId poolId,\n ShareClassId scId,\n AssetId payoutAssetId,\n uint32 nowRedeemEpochId,\n uint128 approvedShareAmount,\n D18 pricePoolPerAsset\n ) external returns (uint128 pendingShareAmount);\n\n /// @notice Emits new shares for the given identifier based on the provided NAV per share.\n /// @dev nowIssueEpochId MUST be called sequentially.\n ///\n /// @param poolId Identifier of the pool\n /// @param scId Identifier of the share class\n /// @param depositAssetId Identifier of the deposit asset for which shares should be issued\n /// @param nowIssueEpochId The epoch for which shares will be issued.\n /// @param navPoolPerShare The nav per share value of the share class (in the pool currency denomination. Conversion\n /// to asset price is done onchain based on the valuation of the asset at approval)\n /// @return issuedShareAmount Amount of shares that have been issued\n function issueShares(\n PoolId poolId,\n ShareClassId scId,\n AssetId depositAssetId,\n uint32 nowIssueEpochId,\n D18 navPoolPerShare\n ) external returns (uint128 issuedShareAmount, uint128 depositAssetAmount, uint128 depositPoolAmount);\n\n /// @notice Take back shares for the given identifier based on the provided NAV per share.\n /// @dev nowRevokeEpochId MUST be called sequentially.\n ///\n /// @param poolId Identifier of the pool\n /// @param scId Identifier of the share class\n /// @param payoutAssetId Identifier of the payout asset\n /// @param nowRevokeEpochId The epoch for which shares will be revoked.\n /// @param navPoolPerShare The nav per share value of the share class (in the pool currency denomination. Conversion\n /// to asset price is done onchain based on the valuation of the asset at approval)\n /// @return revokedShareAmount Amount of shares that have been revoked\n /// @return payoutAssetAmount Converted amount of payout asset based on number of revoked shares\n /// @return payoutPoolAmount Converted amount of pool currency based on number of revoked shares\n function revokeShares(\n PoolId poolId,\n ShareClassId scId,\n AssetId payoutAssetId,\n uint32 nowRevokeEpochId,\n D18 navPoolPerShare\n ) external returns (uint128 revokedShareAmount, uint128 payoutAssetAmount, uint128 payoutPoolAmount);\n\n /// @notice Collects shares for an investor after their deposit request was (partially) approved and new shares were\n /// issued.\n ///\n /// @param poolId Identifier of the pool\n /// @param scId Identifier of the share class\n /// @param investor Centrifuge Vault address of the recipient of the claimed share class tokens\n /// @param depositAssetId Identifier of the asset which the investor used for their deposit request\n /// @return payoutShareAmount Amount of shares which the investor receives\n /// @return paymentAssetAmount Amount of deposit asset which was taken as payment\n /// @return cancelledAssetAmount Amount of deposit asset which was cancelled due to being queued\n /// @return canClaimAgain Whether another call to claimRedeem is needed until investor has fully claimed investments\n function claimDeposit(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId depositAssetId)\n external\n returns (\n uint128 payoutShareAmount,\n uint128 paymentAssetAmount,\n uint128 cancelledAssetAmount,\n bool canClaimAgain\n );\n\n /// @notice Collects an asset amount for an investor after their redeem request was (partially) approved and shares\n /// were revoked.\n ///\n /// @param poolId Identifier of the pool\n /// @param scId Identifier of the share class\n /// @param investor Centrifuge Vault address of the recipient of the claimed asset amount\n /// @param payoutAssetId Identifier of the asset which the investor requested to receive back for their redeemed\n /// shares\n /// @return payoutAssetAmount Amount of payout amount which the investor receives\n /// @return paymentShareAmount Amount of shares which the investor redeemed\n /// @return cancelledShareAmount Amount of shares which were cancelled due to being queued\n /// @return canClaimAgain Whether another call to claimRedeem is needed until investor has fully claimed redemptions\n function claimRedeem(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId payoutAssetId)\n external\n returns (\n uint128 payoutAssetAmount,\n uint128 paymentShareAmount,\n uint128 cancelledShareAmount,\n bool canClaimAgain\n );\n\n /// @notice Increases the share class issuance\n ///\n /// @param poolId Identifier of the pool\n /// @param scId Identifier of the share class\n /// @param amount The amount to increase the share class issuance by\n function increaseShareClassIssuance(PoolId poolId, ShareClassId scId, uint128 amount) external;\n\n /// @notice Decreases the share class issuance\n ///\n /// @param poolId Identifier of the pool\n /// @param scId Identifier of the share class\n /// @param amount The amount to decrease the share class issuance by\n function decreaseShareClassIssuance(PoolId poolId, ShareClassId scId, uint128 amount) external;\n\n /// @notice Adds a new share class to the given pool.\n ///\n /// @param poolId Identifier of the pool\n /// @param name The name of the share class\n /// @param symbol The symbol of the share class\n /// @param salt The salt used for deploying the share class tokens\n /// @return scId Identifier of the newly added share class\n function addShareClass(PoolId poolId, string calldata name, string calldata symbol, bytes32 salt)\n external\n returns (ShareClassId scId);\n\n /// @notice Updates the price pool unit per share unit of a share class\n ///\n /// @param poolId Identifier of the pool\n /// @param scId Identifier of the share class\n /// @param pricePoolPerShare The price per share of the share class (in the pool currency denomination)\n function updatePricePerShare(PoolId poolId, ShareClassId scId, D18 pricePoolPerShare) external;\n\n /// @notice Updates the metadata of a share class.\n ///\n /// @param poolId Identifier of the pool\n /// @param scId Identifier of the share class\n /// @param name The name of the share class\n /// @param symbol The symbol of the share class\n function updateMetadata(PoolId poolId, ShareClassId scId, string calldata name, string calldata symbol) external;\n\n /// @notice Returns the number of share classes for the given pool\n ///\n /// @param poolId Identifier of the pool in question\n /// @return count Number of share classes for the given pool\n function shareClassCount(PoolId poolId) external view returns (uint32 count);\n\n /// @notice Checks the existence of a share class.\n ///\n /// @param poolId Identifier of the pool\n /// @param scId Identifier of the share class\n function exists(PoolId poolId, ShareClassId scId) external view returns (bool);\n\n /// @notice Returns the current ongoing epoch id for deposits\n ///\n /// @param scId Identifier of the share class\n /// @param depositAssetId AssetId of the payment asset\n function nowDepositEpoch(ShareClassId scId, AssetId depositAssetId) external view returns (uint32);\n\n /// @notice Returns the epoch for which will be issued next\n ///\n /// @param scId Identifier of the share class\n /// @param depositAssetId AssetId of the payment asset\n function nowIssueEpoch(ShareClassId scId, AssetId depositAssetId) external view returns (uint32);\n\n /// @notice Returns the current ongoing epoch id for deposits\n ///\n /// @param scId Identifier of the share class\n /// @param payoutAssetId AssetId of the payment asset\n function nowRedeemEpoch(ShareClassId scId, AssetId payoutAssetId) external view returns (uint32);\n\n /// @notice Returns the epoch for which will be revoked next\n ///\n /// @param scId Identifier of the share class\n /// @param depositAssetId AssetId of the payment asset\n function nowRevokeEpoch(ShareClassId scId, AssetId depositAssetId) external view returns (uint32);\n\n /// @notice Returns an upper bound for possible calls to `function claimDeposit(..)`\n ///\n /// @param scId Identifier of the share class\n /// @param investor Recipient of the share class tokens\n /// @param depositAssetId AssetId of the payment asset\n function maxDepositClaims(ShareClassId scId, bytes32 investor, AssetId depositAssetId)\n external\n view\n returns (uint32 maxClaims);\n\n /// @notice Returns an upper bound for possible calls to `function claimRedeem(..)`\n ///\n /// @param scId Identifier of the share class\n /// @param investor Recipient of the payout assets\n /// @param payoutAssetId AssetId of the payout asset\n function maxRedeemClaims(ShareClassId scId, bytes32 investor, AssetId payoutAssetId)\n external\n view\n returns (uint32 maxClaims);\n\n /// @notice Exposes relevant metrics for a share class\n ///\n /// @return totalIssuance The total number of shares known to the CP side\n /// @return pricePoolPerShare The amount of pool units per unit share\n function metrics(ShareClassId scId) external view returns (uint128 totalIssuance, D18 pricePoolPerShare);\n\n /// @notice Determines the next share class id for the given pool.\n ///\n /// @param poolId Identifier of the pool\n /// @return scId Identifier of the next share class\n function previewNextShareClassId(PoolId poolId) external view returns (ShareClassId scId);\n\n /// @notice Determines the share class id for the given pool and index.\n ///\n /// @param poolId Identifier of the pool\n /// @param index The pool-internal index of the share class id\n /// @return scId Identifier of the underlying share class\n function previewShareClassId(PoolId poolId, uint32 index) external pure returns (ShareClassId scId);\n\n /// @notice returns The metadata of the share class.\n ///\n /// @param scId Identifier of the share class\n /// @return name The registered name of the share class token\n /// @return symbol The registered symbol of the share class token\n /// @return salt The registered salt of the share class token, used for deterministic deployments\n function metadata(ShareClassId scId) external returns (string memory name, string memory symbol, bytes32 salt);\n}\n" + }, + "src/misc/Auth.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IAuth} from \"src/misc/interfaces/IAuth.sol\";\n\n/// @title Auth\n/// @notice Simple authentication pattern\n/// @author Based on code from https://github.com/makerdao/dss\nabstract contract Auth is IAuth {\n /// @inheritdoc IAuth\n mapping(address => uint256) public wards;\n\n constructor(address initialWard) {\n wards[initialWard] = 1;\n emit Rely(initialWard);\n }\n\n /// @dev Check if the msg.sender has permissions\n modifier auth() {\n require(wards[msg.sender] == 1, NotAuthorized());\n _;\n }\n\n /// @inheritdoc IAuth\n function rely(address user) public auth {\n wards[user] = 1;\n emit Rely(user);\n }\n\n /// @inheritdoc IAuth\n function deny(address user) public auth {\n wards[user] = 0;\n emit Deny(user);\n }\n}\n" + }, + "src/misc/BaseValuation.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IBaseValuation} from \"src/misc/interfaces/IBaseValuation.sol\";\nimport {IERC6909Decimals} from \"src/misc/interfaces/IERC6909.sol\";\n\nimport {Auth} from \"src/misc/Auth.sol\";\n\nabstract contract BaseValuation is Auth, IBaseValuation {\n /// @notice ERC6909 dependency.\n IERC6909Decimals public erc6909;\n\n constructor(IERC6909Decimals erc6909_, address deployer) Auth(deployer) {\n erc6909 = erc6909_;\n }\n\n /// @inheritdoc IBaseValuation\n function file(bytes32 what, address data) external auth {\n if (what == \"erc6909\") erc6909 = IERC6909Decimals(data);\n else revert FileUnrecognizedParam();\n\n emit File(what, data);\n }\n\n /// @notice Obtain the correct decimals given an asset address\n function _getDecimals(address asset) internal view returns (uint8) {\n return erc6909.decimals(uint160(asset));\n }\n}\n" + }, + "src/misc/ERC20.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {EIP712Lib} from \"src/misc/libraries/EIP712Lib.sol\";\nimport {SignatureLib} from \"src/misc/libraries/SignatureLib.sol\";\n\nimport {IERC20, IERC20Metadata, IERC20Permit} from \"src/misc/interfaces/IERC20.sol\";\n\n/// @title ERC20\n/// @notice Standard ERC-20 implementation, with mint/burn functionality and permit logic.\n/// @author Modified from https://github.com/makerdao/xdomain-dss/blob/master/src/Dai.sol\ncontract ERC20 is Auth, IERC20Metadata, IERC20Permit {\n error FileUnrecognizedParam();\n\n /// @inheritdoc IERC20Metadata\n string public name;\n /// @inheritdoc IERC20Metadata\n string public symbol;\n /// @inheritdoc IERC20Metadata\n uint8 public immutable decimals;\n /// @inheritdoc IERC20\n uint256 public totalSupply;\n\n mapping(address => uint256) private balances;\n\n /// @inheritdoc IERC20\n mapping(address => mapping(address => uint256)) public allowance;\n /// @inheritdoc IERC20Permit\n mapping(address => uint256) public nonces;\n\n // --- EIP712 ---\n bytes32 private immutable nameHash;\n bytes32 private immutable versionHash;\n uint256 public immutable deploymentChainId;\n bytes32 private immutable _DOMAIN_SEPARATOR;\n bytes32 public constant PERMIT_TYPEHASH =\n keccak256(\"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\");\n\n // --- Events ---\n event File(bytes32 indexed what, string data);\n\n constructor(uint8 decimals_) Auth(msg.sender) {\n decimals = decimals_;\n\n nameHash = keccak256(bytes(\"Centrifuge\"));\n versionHash = keccak256(bytes(\"1\"));\n deploymentChainId = block.chainid;\n _DOMAIN_SEPARATOR = EIP712Lib.calculateDomainSeparator(nameHash, versionHash);\n }\n\n function _balanceOf(address user) internal view virtual returns (uint256) {\n return balances[user];\n }\n\n /// @inheritdoc IERC20\n function balanceOf(address user) public view virtual returns (uint256) {\n return _balanceOf(user);\n }\n\n function _setBalance(address user, uint256 value) internal virtual {\n balances[user] = value;\n }\n\n /// @inheritdoc IERC20Permit\n function DOMAIN_SEPARATOR() public view returns (bytes32) {\n return block.chainid == deploymentChainId\n ? _DOMAIN_SEPARATOR\n : EIP712Lib.calculateDomainSeparator(nameHash, versionHash);\n }\n\n // --- Administration ---\n function file(bytes32 what, string memory data) public virtual auth {\n if (what == \"name\") name = data;\n else if (what == \"symbol\") symbol = data;\n else revert FileUnrecognizedParam();\n emit File(what, data);\n }\n\n // --- ERC20 Mutations ---\n /// @inheritdoc IERC20\n function transfer(address to, uint256 value) public virtual returns (bool) {\n require(to != address(0) && to != address(this), InvalidAddress());\n uint256 balance = balanceOf(msg.sender);\n require(balance >= value, InsufficientBalance());\n\n unchecked {\n _setBalance(msg.sender, balance - value);\n // note: we don't need an overflow check here b/c sum of all balances == totalSupply\n _setBalance(to, _balanceOf(to) + value);\n }\n\n emit Transfer(msg.sender, to, value);\n\n return true;\n }\n\n /// @inheritdoc IERC20\n function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {\n return _transferFrom(msg.sender, from, to, value);\n }\n\n function _transferFrom(address sender, address from, address to, uint256 value) internal virtual returns (bool) {\n require(to != address(0) && to != address(this), InvalidAddress());\n uint256 balance = balanceOf(from);\n require(balance >= value, InsufficientBalance());\n\n if (from != sender) {\n uint256 allowed = allowance[from][sender];\n if (allowed != type(uint256).max) {\n require(allowed >= value, InsufficientAllowance());\n unchecked {\n allowance[from][sender] = allowed - value;\n }\n }\n }\n\n unchecked {\n _setBalance(from, balance - value);\n // note: we don't need an overflow check here b/c sum of all balances == totalSupply\n _setBalance(to, _balanceOf(to) + value);\n }\n\n emit Transfer(from, to, value);\n\n return true;\n }\n\n /// @inheritdoc IERC20\n function approve(address spender, uint256 value) external returns (bool) {\n allowance[msg.sender][spender] = value;\n\n emit Approval(msg.sender, spender, value);\n\n return true;\n }\n\n // --- Mint/Burn ---\n function mint(address to, uint256 value) public virtual auth {\n require(to != address(0) && to != address(this), InvalidAddress());\n unchecked {\n // We don't need an overflow check here b/c balances[to] <= totalSupply\n // and there is an overflow check below\n _setBalance(to, _balanceOf(to) + value);\n }\n totalSupply += value;\n\n emit Transfer(address(0), to, value);\n }\n\n function burn(address from, uint256 value) public virtual auth {\n uint256 balance = balanceOf(from);\n require(balance >= value, InsufficientBalance());\n\n if (from != msg.sender) {\n uint256 allowed = allowance[from][msg.sender];\n if (allowed != type(uint256).max) {\n require(allowed >= value, InsufficientAllowance());\n\n unchecked {\n allowance[from][msg.sender] = allowed - value;\n }\n }\n }\n\n unchecked {\n // We don't need overflow checks b/c require(balance >= value) and balance <= totalSupply\n _setBalance(from, balance - value);\n totalSupply -= value;\n }\n\n emit Transfer(from, address(0), value);\n }\n\n // --- Approve by signature ---\n function permit(address owner, address spender, uint256 value, uint256 deadline, bytes memory signature) public {\n require(block.timestamp <= deadline, PermitExpired());\n\n uint256 nonce;\n unchecked {\n nonce = nonces[owner]++;\n }\n\n bytes32 digest = keccak256(\n abi.encodePacked(\n \"\\x19\\x01\",\n DOMAIN_SEPARATOR(),\n keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonce, deadline))\n )\n );\n\n require(SignatureLib.isValidSignature(owner, digest, signature), InvalidPermit());\n\n allowance[owner][spender] = value;\n emit Approval(owner, spender, value);\n }\n\n /// @inheritdoc IERC20Permit\n function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)\n external\n {\n permit(owner, spender, value, deadline, abi.encodePacked(r, s, v));\n }\n}\n" + }, + "src/misc/IdentityValuation.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {d18} from \"src/misc/types/D18.sol\";\nimport {IERC7726} from \"src/misc/interfaces/IERC7726.sol\";\nimport {IIdentityValuation} from \"src/misc/interfaces/IIdentityValuation.sol\";\nimport {IERC6909Decimals} from \"src/misc/interfaces/IERC6909.sol\";\nimport {BaseValuation} from \"src/misc/BaseValuation.sol\";\n\nimport {PricingLib} from \"src/common/libraries/PricingLib.sol\";\n\ncontract IdentityValuation is BaseValuation, IIdentityValuation {\n constructor(IERC6909Decimals erc6909, address deployer) BaseValuation(erc6909, deployer) {}\n\n /// @inheritdoc IERC7726\n function getQuote(uint256 baseAmount, address base, address quote) external view returns (uint256 quoteAmount) {\n return PricingLib.convertWithPrice(baseAmount, _getDecimals(base), _getDecimals(quote), d18(1e18));\n }\n}\n" + }, + "src/misc/Multicall.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.28;\n\n// NOTE: This file has warning disabled due https://github.com/ethereum/solidity/issues/14359\n// If perform any change on it, please ensure no other warnings appears\n\nimport {IMulticall} from \"src/misc/interfaces/IMulticall.sol\";\nimport {ReentrancyProtection} from \"src/misc/ReentrancyProtection.sol\";\n\nabstract contract Multicall is ReentrancyProtection, IMulticall {\n function multicall(bytes[] calldata data) public payable virtual protected {\n uint256 totalBytes = data.length;\n for (uint256 i; i < totalBytes; ++i) {\n (bool success, bytes memory returnData) = address(this).delegatecall(data[i]);\n if (!success) {\n uint256 length = returnData.length;\n require(length != 0, CallFailedWithEmptyRevert());\n\n assembly (\"memory-safe\") {\n revert(add(32, returnData), length)\n }\n }\n }\n }\n}\n" + }, + "src/misc/Recoverable.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {IERC6909} from \"src/misc/interfaces/IERC6909.sol\";\nimport {SafeTransferLib} from \"src/misc/libraries/SafeTransferLib.sol\";\n\nimport {IRecoverable, ETH_ADDRESS} from \"src/misc/interfaces/IRecoverable.sol\";\n\nabstract contract Recoverable is Auth, IRecoverable {\n /// @inheritdoc IRecoverable\n function recoverTokens(address token, address receiver, uint256 amount) public auth {\n if (token == ETH_ADDRESS) {\n SafeTransferLib.safeTransferETH(receiver, amount);\n } else {\n SafeTransferLib.safeTransfer(token, receiver, amount);\n }\n }\n\n /// @inheritdoc IRecoverable\n function recoverTokens(address token, uint256 tokenId, address receiver, uint256 amount) external auth {\n if (tokenId == 0) {\n recoverTokens(token, receiver, amount);\n } else {\n IERC6909(token).transfer(receiver, tokenId, amount);\n }\n }\n}\n" + }, + "src/misc/ReentrancyProtection.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.28;\n\n// NOTE: This file has warning disabled due https://github.com/ethereum/solidity/issues/14359\n// If perform any change on it, please ensure no other warnings appears\n\nabstract contract ReentrancyProtection {\n /// @notice Dispatched when there is a re-entrancy issue\n error UnauthorizedSender();\n\n address private transient _initiator;\n\n /// @dev The method is protected for reentrancy issues.\n modifier protected() {\n if (_initiator == address(0)) {\n // Single call re-entrancy lock\n _initiator = msg.sender;\n _;\n _initiator = address(0);\n } else {\n // Multicall re-entrancy lock\n require(msg.sender == _initiator, UnauthorizedSender());\n _;\n }\n }\n}\n" + }, + "src/misc/interfaces/IAuth.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\ninterface IAuth {\n event Rely(address indexed user);\n event Deny(address indexed user);\n\n error NotAuthorized();\n\n /// @notice Returns whether the target is a ward (has admin access)\n function wards(address target) external view returns (uint256);\n\n /// @notice Make user a ward (give them admin access)\n function rely(address user) external;\n\n /// @notice Remove user as a ward (remove admin access)\n function deny(address user) external;\n}\n" + }, + "src/misc/interfaces/IBaseValuation.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IERC7726} from \"src/misc/interfaces/IERC7726.sol\";\n\n/// Provides a base implementation for all ERC7726 valuation in the system\ninterface IBaseValuation is IERC7726 {\n /// @notice Emitted when a call to `file()` was performed.\n event File(bytes32 indexed what, address addr);\n\n /// @notice Dispatched when the `what` parameter of `file()` is not supported by the implementation.\n error FileUnrecognizedParam();\n\n /// @notice Updates a contract parameter.\n /// @param what Name of the parameter to update.\n /// Accepts a `bytes32` representation of 'assetRegistry' string value.\n /// @param data New value given to the `what` parameter\n function file(bytes32 what, address data) external;\n}\n" + }, + "src/misc/interfaces/IERC20.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\n/// @title IERC20\n/// @dev Interface of the ERC20 standard as defined in the EIP.\n/// @author Modified from OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)\ninterface IERC20 {\n error InvalidAddress();\n error InsufficientBalance();\n error InsufficientAllowance();\n\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n error PermitExpired();\n error InvalidPermit();\n\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)\n external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\ninterface IERC20Wrapper {\n /**\n * @dev Returns the address of the underlying ERC-20 token that is being wrapped.\n */\n function underlying() external view returns (address);\n\n /**\n * @dev Allow a user to deposit underlying tokens and mint the corresponding number of wrapped tokens.\n */\n function depositFor(address account, uint256 value) external returns (bool);\n\n /**\n * @dev Allow a user to burn a number of wrapped tokens and withdraw the corresponding number of underlying tokens.\n */\n function withdrawTo(address account, uint256 value) external returns (bool);\n}\n" + }, + "src/misc/interfaces/IERC6909.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IERC165} from \"forge-std/interfaces/IERC165.sol\";\n\ninterface IERC6909 is IERC165 {\n error EmptyOwner();\n error EmptyAmount();\n error InvalidTokenId();\n error InsufficientBalance(address owner, uint256 tokenId);\n error InsufficientAllowance(address sender, uint256 tokenId);\n\n event OperatorSet(address indexed owner, address indexed operator, bool approved);\n event Approval(address indexed owner, address indexed spender, uint256 indexed tokenId, uint256 amount);\n event Transfer(address caller, address indexed from, address indexed to, uint256 indexed tokenId, uint256 amount);\n\n /// @notice Owner balance of a tokenId.\n /// @param owner The address of the owner.\n /// @param tokenId The id of the token.\n /// @return amount The balance of the token.\n function balanceOf(address owner, uint256 tokenId) external view returns (uint256 amount);\n\n /// @notice Spender allowance of a tokenId.\n /// @param owner The address of the owner.\n /// @param spender The address of the spender.\n /// @param tokenId The id of the token.\n /// @return amount The allowance of the token.\n function allowance(address owner, address spender, uint256 tokenId) external view returns (uint256 amount);\n\n /// @notice Checks if a spender is approved by an owner as an operator.\n /// @param owner The address of the owner.\n /// @param spender The address of the spender.\n /// @return approved The approval status.\n function isOperator(address owner, address spender) external view returns (bool approved);\n\n /// @notice Transfers an amount of a tokenId from the caller to a receiver.\n /// @param receiver The address of the receiver.\n /// @param tokenId The id of the token.\n /// @param amount The amount of the token.\n /// @return bool True, always, unless the function reverts.\n function transfer(address receiver, uint256 tokenId, uint256 amount) external returns (bool);\n\n /// @notice Transfers an amount of a tokenId from a sender to a receiver.\n /// @param sender The address of the sender.\n /// @param receiver The address of the receiver.\n /// @param tokenId The id of the token.\n /// @param amount The amount of the token.\n /// @return bool True, always, unless the function reverts.\n function transferFrom(address sender, address receiver, uint256 tokenId, uint256 amount) external returns (bool);\n\n /// @notice Approves an amount of a tokenId to a spender.\n /// @param spender The address of the spender.\n /// @param tokenId The id of the token.\n /// @param amount The amount of the token.\n /// @return bool True, always.\n function approve(address spender, uint256 tokenId, uint256 amount) external returns (bool);\n\n /// @notice Sets or removes an operator for the caller.\n /// @param operator The address of the operator.\n /// @param approved The approval status.\n /// @return bool True, always.\n function setOperator(address operator, bool approved) external returns (bool);\n}\n\ninterface IERC6909URIExt {\n event TokenURISet(uint256 indexed tokenId, string uri);\n event ContractURISet(address indexed target, string uri);\n\n error EmptyURI();\n\n /// @return uri Returns the common token URI.\n function contractURI() external view returns (string memory);\n\n /// @dev Returns empty string if tokenId does not exist.\n /// MAY implemented to throw MissingURI(tokenId) error.\n /// @param tokenId The token to query URI for.\n /// @return uri A string representing the uri for the specific tokenId.\n function tokenURI(uint256 tokenId) external view returns (string memory);\n}\n\ninterface IERC6909NFT is IERC6909, IERC6909URIExt {\n error UnknownTokenId(address owner, uint256 tokenId);\n error LessThanMinimalDecimal(uint8 minimal, uint8 actual);\n\n /// @notice Provide URI for a specific tokenId.\n /// @param tokenId Token Id.\n /// @param URI URI to a document defining the collection as a whole.\n function setTokenURI(uint256 tokenId, string memory URI) external;\n\n /// @dev Optional method to set up the contract URI if needed.\n /// @param URI URI to a document defining the collection as a whole.\n function setContractURI(string memory URI) external;\n\n /// @notice Mint new tokens for a given owner and sets tokenURI.\n /// @dev For non-fungible tokens, call with amount = 1, for fungible it could be any amount.\n /// TokenId is auto incremented by one.\n ///\n /// @param owner Creates supply of a given tokenId by amount for owner.\n /// @param tokenURI URI fortestBurningToken the newly minted token.\n /// @return tokenId Id of the newly minted token.\n function mint(address owner, string memory tokenURI) external returns (uint256 tokenId);\n\n /// @notice Destroy supply of a given tokenId by amount.\n /// @dev The msg.sender MUST be the owner.\n ///\n /// @param tokenId Item which have reduced supply.\n function burn(uint256 tokenId) external;\n}\n\n/// @notice Extension of ERC6909 Standard for tracking total supply\ninterface IERC6909TotalSupplyExt {\n /// @notice The totalSupply for a token id.\n ///\n /// @param tokenId Id of the token\n /// @return supply Total supply for a given `tokenId`\n function totalSupply(uint256 tokenId) external returns (uint256 supply);\n}\n\ninterface IERC6909Decimals {\n /// @notice Used to retrieve the decimals of an asset\n /// @dev address is used but the value corresponds to a AssetId\n function decimals(uint256 assetId) external view returns (uint8);\n}\n\ninterface IERC6909MetadataExt is IERC6909Decimals {\n /// @notice Used to retrieve the decimals of an asset\n /// @dev address is used but the value corresponds to a AssetId\n function decimals(uint256 assetId) external view returns (uint8);\n\n /// @notice Used to retrieve the name of an asset\n /// @dev address is used but the value corresponds to a AssetId\n function name(uint256 assetId) external view returns (string memory);\n\n /// @notice Used to retrieve the symbol of an asset\n /// @dev address is used but the value corresponds to a AssetId\n function symbol(uint256 assetId) external view returns (string memory);\n}\n\ninterface IERC6909Fungible is IERC6909 {\n /// @notice Mint new tokens for a specific tokenid and assign them to an owner\n ///\n /// @param owner Creates supply of a given `tokenId` by `amount` for owner.\n /// @param tokenId Id of the item\n /// @param amount Adds `amount` to the total supply of the given `tokenId`\n function mint(address owner, uint256 tokenId, uint256 amount) external;\n\n /// @notice Destroy supply of a given tokenId by amount.\n /// @dev The msg.sender MUST be the owner.\n ///\n /// @param owner Owner of the `tokenId`\n /// @param tokenId Id of the item.\n /// @param amount Subtract `amount` from the total supply of the given `tokenId`\n function burn(address owner, uint256 tokenId, uint256 amount) external;\n\n /// @notice Enforces a transfer from `spender` point of view.\n ///\n ///\n /// @param sender The owner of the `tokenId`\n /// @param receiver Address of the receiving party\n /// @param tokenId Token Id\n /// @param amount Amount to be transferred\n function authTransferFrom(address sender, address receiver, uint256 tokenId, uint256 amount)\n external\n returns (bool);\n}\n\n/// @dev A factory contract to deploy new collateral contracts implementing IERC6909.\ninterface IERC6909Factory {\n /// Events\n event NewTokenDeployment(address indexed owner, address instance);\n\n /// @notice Deploys new install of a contract that implements IERC6909.\n /// @dev Factory should deploy deterministically if possible.\n ///\n /// @param owner Owner of the deployed collateral contract which has initial full rights.\n /// @param salt Used to make a deterministic deployment.\n /// @return An address of the newly deployed contract.\n function deploy(address owner, bytes32 salt) external returns (address);\n\n /// @notice Generates a new deterministic address based on the owner and the salt.\n ///\n /// @param owner Owner of the deployed collateral contract which has initial full rights.\n /// @param salt Used to make a deterministic deployment.\n /// @return An address of the newly deployed contract.\n function previewAddress(address owner, bytes32 salt) external returns (address);\n}\n" + }, + "src/misc/interfaces/IERC7540.sol": { + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.5.0;\n\nimport {IRecoverable} from \"src/misc/interfaces/IRecoverable.sol\";\nimport {IERC7575, IERC165} from \"src/misc/interfaces/IERC7575.sol\";\n\ninterface IERC7540Operator {\n /**\n * @dev The event emitted when an operator is set.\n *\n * @param controller The address of the controller.\n * @param operator The address of the operator.\n * @param approved The approval status.\n */\n event OperatorSet(address indexed controller, address indexed operator, bool approved);\n\n /**\n * @dev Sets or removes an operator for the caller.\n *\n * @param operator The address of the operator.\n * @param approved The approval status.\n * @return Whether the call was executed successfully or not\n */\n function setOperator(address operator, bool approved) external returns (bool);\n\n /**\n * @dev Returns `true` if the `operator` is approved as an operator for an `controller`.\n *\n * @param controller The address of the controller.\n * @param operator The address of the operator.\n * @return status The approval status\n */\n function isOperator(address controller, address operator) external view returns (bool status);\n}\n\ninterface IERC7540Deposit is IERC7540Operator {\n event DepositRequest(\n address indexed controller, address indexed owner, uint256 indexed requestId, address sender, uint256 assets\n );\n /**\n * @dev Transfers assets from sender into the Vault and submits a Request for asynchronous deposit.\n *\n * - MUST support ERC-20 approve / transferFrom on asset as a deposit Request flow.\n * - MUST revert if all of assets cannot be requested for deposit.\n * - owner MUST be msg.sender unless some unspecified explicit approval is given by the caller,\n * approval of ERC-20 tokens from owner to sender is NOT enough.\n *\n * @param assets the amount of deposit assets to transfer from owner\n * @param controller the controller of the request who will be able to operate the request\n * @param owner the source of the deposit assets\n *\n * NOTE: most implementations will require pre-approval of the Vault with the Vault's underlying asset token.\n */\n\n function requestDeposit(uint256 assets, address controller, address owner) external returns (uint256 requestId);\n\n /**\n * @dev Returns the amount of requested assets in Pending state.\n *\n * - MUST NOT include any assets in Claimable state for deposit or mint.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT revert unless due to integer overflow caused by an unreasonably large input.\n */\n function pendingDepositRequest(uint256 requestId, address controller)\n external\n view\n returns (uint256 pendingAssets);\n\n /**\n * @dev Returns the amount of requested assets in Claimable state for the controller to deposit or mint.\n *\n * - MUST NOT include any assets in Pending state.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT revert unless due to integer overflow caused by an unreasonably large input.\n */\n function claimableDepositRequest(uint256 requestId, address controller)\n external\n view\n returns (uint256 claimableAssets);\n\n /**\n * @dev Mints shares Vault shares to receiver by claiming the Request of the controller.\n *\n * - MUST emit the Deposit event.\n * - controller MUST equal msg.sender unless the controller has approved the msg.sender as an operator.\n */\n function deposit(uint256 assets, address receiver, address controller) external returns (uint256 shares);\n\n /**\n * @dev Mints exactly shares Vault shares to receiver by claiming the Request of the controller.\n *\n * - MUST emit the Deposit event.\n * - controller MUST equal msg.sender unless the controller has approved the msg.sender as an operator.\n */\n function mint(uint256 shares, address receiver, address controller) external returns (uint256 assets);\n}\n\ninterface IERC7540Redeem is IERC7540Operator {\n event RedeemRequest(\n address indexed controller, address indexed owner, uint256 indexed requestId, address sender, uint256 assets\n );\n\n /**\n * @dev Assumes control of shares from sender into the Vault and submits a Request for asynchronous redeem.\n *\n * - MUST support a redeem Request flow where the control of shares is taken from sender directly\n * where msg.sender has ERC-20 approval over the shares of owner.\n * - MUST revert if all of shares cannot be requested for redeem.\n *\n * @param shares the amount of shares to be redeemed to transfer from owner\n * @param controller the controller of the request who will be able to operate the request\n * @param owner the source of the shares to be redeemed\n *\n * NOTE: most implementations will require pre-approval of the Vault with the Vault's share token.\n */\n function requestRedeem(uint256 shares, address controller, address owner) external returns (uint256 requestId);\n\n /**\n * @dev Returns the amount of requested shares in Pending state.\n *\n * - MUST NOT include any shares in Claimable state for redeem or withdraw.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT revert unless due to integer overflow caused by an unreasonably large input.\n */\n function pendingRedeemRequest(uint256 requestId, address controller)\n external\n view\n returns (uint256 pendingShares);\n\n /**\n * @dev Returns the amount of requested shares in Claimable state for the controller to redeem or withdraw.\n *\n * - MUST NOT include any shares in Pending state for redeem or withdraw.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT revert unless due to integer overflow caused by an unreasonably large input.\n */\n function claimableRedeemRequest(uint256 requestId, address controller)\n external\n view\n returns (uint256 claimableShares);\n}\n\ninterface IERC7887Deposit {\n event CancelDepositRequest(address indexed controller, uint256 indexed requestId, address sender);\n event CancelDepositClaim(\n address indexed controller, address indexed receiver, uint256 indexed requestId, address sender, uint256 assets\n );\n\n /**\n * @dev Submits a Request for cancelling the pending deposit Request\n *\n * - controller MUST be msg.sender unless some unspecified explicit approval is given by the caller,\n * approval of ERC-20 tokens from controller to sender is NOT enough.\n * - MUST set pendingCancelDepositRequest to `true` for the returned requestId after request\n * - MUST increase claimableCancelDepositRequest for the returned requestId after fulfillment\n * - SHOULD be claimable using `claimCancelDepositRequest`\n * Note: while `pendingCancelDepositRequest` is `true`, `requestDeposit` cannot be called\n */\n function cancelDepositRequest(uint256 requestId, address controller) external;\n\n /**\n * @dev Returns whether the deposit Request is pending cancelation\n *\n * - MUST NOT show any variations depending on the caller.\n */\n function pendingCancelDepositRequest(uint256 requestId, address controller)\n external\n view\n returns (bool isPending);\n\n /**\n * @dev Returns the amount of assets that were canceled from a deposit Request, and can now be claimed.\n *\n * - MUST NOT show any variations depending on the caller.\n */\n function claimableCancelDepositRequest(uint256 requestId, address controller)\n external\n view\n returns (uint256 claimableAssets);\n\n /**\n * @dev Claims the canceled deposit assets, and removes the pending cancelation Request\n *\n * - controller MUST be msg.sender unless some unspecified explicit approval is given by the caller,\n * approval of ERC-20 tokens from controller to sender is NOT enough.\n * - MUST set pendingCancelDepositRequest to `false` for the returned requestId after request\n * - MUST set claimableCancelDepositRequest to 0 for the returned requestId after fulfillment\n */\n function claimCancelDepositRequest(uint256 requestId, address receiver, address controller)\n external\n returns (uint256 assets);\n}\n\ninterface IERC7887Redeem {\n event CancelRedeemRequest(address indexed controller, uint256 indexed requestId, address sender);\n event CancelRedeemClaim(\n address indexed controller, address indexed receiver, uint256 indexed requestId, address sender, uint256 shares\n );\n\n /**\n * @dev Submits a Request for cancelling the pending redeem Request\n *\n * - controller MUST be msg.sender unless some unspecified explicit approval is given by the caller,\n * approval of ERC-20 tokens from controller to sender is NOT enough.\n * - MUST set pendingCancelRedeemRequest to `true` for the returned requestId after request\n * - MUST increase claimableCancelRedeemRequest for the returned requestId after fulfillment\n * - SHOULD be claimable using `claimCancelRedeemRequest`\n * Note: while `pendingCancelRedeemRequest` is `true`, `requestRedeem` cannot be called\n */\n function cancelRedeemRequest(uint256 requestId, address controller) external;\n\n /**\n * @dev Returns whether the redeem Request is pending cancelation\n *\n * - MUST NOT show any variations depending on the caller.\n */\n function pendingCancelRedeemRequest(uint256 requestId, address controller) external view returns (bool isPending);\n\n /**\n * @dev Returns the amount of shares that were canceled from a redeem Request, and can now be claimed.\n *\n * - MUST NOT show any variations depending on the caller.\n */\n function claimableCancelRedeemRequest(uint256 requestId, address controller)\n external\n view\n returns (uint256 claimableShares);\n\n /**\n * @dev Claims the canceled redeem shares, and removes the pending cancelation Request\n *\n * - controller MUST be msg.sender unless some unspecified explicit approval is given by the caller,\n * approval of ERC-20 tokens from controller to sender is NOT enough.\n * - MUST set pendingCancelRedeemRequest to `false` for the returned requestId after request\n * - MUST set claimableCancelRedeemRequest to 0 for the returned requestId after fulfillment\n */\n function claimCancelRedeemRequest(uint256 requestId, address receiver, address controller)\n external\n returns (uint256 shares);\n}\n\ninterface IERC7741 {\n /**\n * @dev Grants or revokes permissions for `operator` to manage Requests on behalf of the\n * `msg.sender`, using an [EIP-712](./eip-712.md) signature.\n */\n function authorizeOperator(\n address controller,\n address operator,\n bool approved,\n bytes32 nonce,\n uint256 deadline,\n bytes memory signature\n ) external returns (bool);\n\n /**\n * @dev Revokes the given `nonce` for `msg.sender` as the `owner`.\n */\n function invalidateNonce(bytes32 nonce) external;\n\n /**\n * @dev Returns whether the given `nonce` has been used for the `controller`.\n */\n function authorizations(address controller, bytes32 nonce) external view returns (bool used);\n\n /**\n * @dev Returns the `DOMAIN_SEPARATOR` as defined according to EIP-712. The `DOMAIN_SEPARATOR\n * should be unique to the contract and chain to prevent replay attacks from other domains,\n * and satisfy the requirements of EIP-712, but is otherwise unconstrained.\n */\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\ninterface IERC7714 {\n /**\n * @dev Returns `true` if the `user` is permissioned to interact with the contract.\n */\n function isPermissioned(address controller) external view returns (bool);\n}\n" + }, + "src/misc/interfaces/IERC7575.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\ninterface IERC7575 is IERC165 {\n event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares);\n event Withdraw(\n address indexed sender, address indexed receiver, address indexed owner, uint256 assets, uint256 shares\n );\n\n /**\n * @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.\n *\n * - MUST be an ERC-20 token contract.\n * - MUST NOT revert.\n */\n function asset() external view returns (address assetTokenAddress);\n\n /**\n * @dev Returns the address of the share token\n *\n * - MUST be an ERC-20 token contract.\n * - MUST NOT revert.\n */\n function share() external view returns (address shareTokenAddress);\n\n /**\n * @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal\n * scenario where all the conditions are met.\n *\n * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.\n * - MUST NOT revert.\n *\n * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the\n * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and\n * from.\n */\n function convertToShares(uint256 assets) external view returns (uint256 shares);\n\n /**\n * @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal\n * scenario where all the conditions are met.\n *\n * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.\n * - MUST NOT revert.\n *\n * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the\n * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and\n * from.\n */\n function convertToAssets(uint256 shares) external view returns (uint256 assets);\n\n /**\n * @dev Returns the total amount of the underlying asset that is “managed” by Vault.\n *\n * - SHOULD include any compounding that occurs from yield.\n * - MUST be inclusive of any fees that are charged against assets in the Vault.\n * - MUST NOT revert.\n */\n function totalAssets() external view returns (uint256 totalManagedAssets);\n\n /**\n * @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,\n * through a deposit call.\n *\n * - MUST return a limited value if receiver is subject to some deposit limit.\n * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.\n * - MUST NOT revert.\n */\n function maxDeposit(address receiver) external view returns (uint256 maxAssets);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given\n * current on-chain conditions.\n *\n * - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit\n * call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called\n * in the same transaction.\n * - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the\n * deposit would be accepted, regardless if the user has enough tokens approved, etc.\n * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by depositing.\n */\n function previewDeposit(uint256 assets) external view returns (uint256 shares);\n\n /**\n * @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens.\n *\n * - MUST emit the Deposit event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n * deposit execution, and are accounted for during deposit.\n * - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not\n * approving enough underlying tokens to the Vault contract, etc).\n *\n * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.\n */\n function deposit(uint256 assets, address receiver) external returns (uint256 shares);\n\n /**\n * @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.\n * - MUST return a limited value if receiver is subject to some mint limit.\n * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.\n * - MUST NOT revert.\n */\n function maxMint(address receiver) external view returns (uint256 maxShares);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given\n * current on-chain conditions.\n *\n * - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call\n * in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the\n * same transaction.\n * - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint\n * would be accepted, regardless if the user has enough tokens approved, etc.\n * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by minting.\n */\n function previewMint(uint256 shares) external view returns (uint256 assets);\n\n /**\n * @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.\n *\n * - MUST emit the Deposit event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint\n * execution, and are accounted for during mint.\n * - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not\n * approving enough underlying tokens to the Vault contract, etc).\n *\n * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.\n */\n function mint(uint256 shares, address receiver) external returns (uint256 assets);\n\n /**\n * @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the\n * Vault, through a withdraw call.\n *\n * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.\n * - MUST NOT revert.\n */\n function maxWithdraw(address owner) external view returns (uint256 maxAssets);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,\n * given current on-chain conditions.\n *\n * - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw\n * call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if\n * called\n * in the same transaction.\n * - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though\n * the withdrawal would be accepted, regardless if the user has enough shares, etc.\n * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by depositing.\n */\n function previewWithdraw(uint256 assets) external view returns (uint256 shares);\n\n /**\n * @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver.\n *\n * - MUST emit the Withdraw event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n * withdraw execution, and are accounted for during withdraw.\n * - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner\n * not having enough shares, etc).\n *\n * Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.\n * Those methods should be performed separately.\n */\n function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares);\n\n /**\n * @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault,\n * through a redeem call.\n *\n * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.\n * - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock.\n * - MUST NOT revert.\n */\n function maxRedeem(address owner) external view returns (uint256 maxShares);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block,\n * given current on-chain conditions.\n *\n * - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call\n * in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the\n * same transaction.\n * - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the\n * redemption would be accepted, regardless if the user has enough shares, etc.\n * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by redeeming.\n */\n function previewRedeem(uint256 shares) external view returns (uint256 assets);\n\n /**\n * @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver.\n *\n * - MUST emit the Withdraw event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n * redeem execution, and are accounted for during redeem.\n * - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner\n * not having enough shares, etc).\n *\n * NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed.\n * Those methods should be performed separately.\n */\n function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets);\n}\n\ninterface IERC7575Share is IERC165 {\n event VaultUpdate(address indexed asset, address vault);\n\n /**\n * @dev Returns the address of the Vault for the given asset.\n *\n * @param asset the ERC-20 token to deposit with into the Vault\n */\n function vault(address asset) external view returns (address);\n}\n" + }, + "src/misc/interfaces/IERC7726.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\n/// [ERC-7726](https://eips.ethereum.org/EIPS/eip-7726): Common Quote Oracle\n/// Interface for asset conversions.\ninterface IERC7726 {\n /// @notice Returns the value of baseAmount of base in quote terms, e.g. 10 ETH (base) in USDC (quote).\n /// @param base The asset in which the baseAmount is denominated in\n /// @param quote The asset in which the user needs to value the baseAmount\n /// @param baseAmount The amount of base in base terms.\n function getQuote(uint256 baseAmount, address base, address quote) external view returns (uint256 quoteAmount);\n}\n" + }, + "src/misc/interfaces/IIdentityValuation.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IERC7726} from \"src/misc/interfaces/IERC7726.sol\";\n\n/// @notice An IERC7726 valuation that always values 1:1.\ninterface IIdentityValuation is IERC7726 {}\n" + }, + "src/misc/interfaces/IMulticall.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\n/// @notice Allows to call several calls of the same contract in a single transaction\ninterface IMulticall {\n /// @notice Dispatched when an empty revert is dispatched in a method in the multicall\n error CallFailedWithEmptyRevert();\n\n /// @notice Allows caller to execute multiple (batched) messages calls in one transaction.\n /// @param data An array of encoded methods of the same contract.\n /// @dev No reentrant execution is allowed.\n /// If one call fails, it reverts the whole transaction.\n /// In order to provide the correct value for functions that require top up,\n /// the caller must estimate separately, in advance, how much each of the message call will cost.\n /// The `msg.value` when calling this method must be the sum of all estimates.\n function multicall(bytes[] calldata data) external payable;\n}\n" + }, + "src/misc/interfaces/IRecoverable.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\naddress constant ETH_ADDRESS = address(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);\n\ninterface IRecoverable {\n /// @notice Used to recover any ERC-20 token.\n /// @dev This method is called only by authorized entities\n /// @param token It could be 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee\n /// to recover locked native ETH or token compatible with ERC20.\n /// @param to Receiver of the funds\n /// @param amount Amount to send to the receiver.\n function recoverTokens(address token, address to, uint256 amount) external;\n\n /// @notice Used to recover any ERC-20 or ERC-6909 token.\n /// @dev This method is called only by authorized entities\n /// @param token It could be 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee\n /// to recover locked native ETH or token compatible with ERC20 or ERC6909.\n /// @param tokenId The token id, i.e. non-zero if the underlying token is ERC6909 and else zero.\n /// @param to Receiver of the funds\n /// @param amount Amount to send to the receiver.\n function recoverTokens(address token, uint256 tokenId, address to, uint256 amount) external;\n}\n" + }, + "src/misc/libraries/ArrayLib.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\n/// @title ArrayLib\nlibrary ArrayLib {\n error InvalidValues();\n\n function countNonZeroValues(uint16[8] memory arr) internal pure returns (uint8 count) {\n uint256 elementsCount = arr.length;\n for (uint256 i; i < elementsCount; i++) {\n if (arr[i] != 0) ++count;\n }\n }\n\n function decreaseFirstNValues(uint16[8] storage arr, uint8 numValues) internal {\n uint256 elementsCount = arr.length;\n for (uint256 i; i < elementsCount; i++) {\n if (numValues == 0) return;\n\n if (arr[i] != 0) {\n arr[i] -= 1;\n numValues--;\n }\n }\n\n require(numValues == 0, InvalidValues());\n }\n\n function isEmpty(uint16[8] memory arr) internal pure returns (bool) {\n uint256 elementsCount = arr.length;\n for (uint256 i; i < elementsCount; i++) {\n if (arr[i] != 0) return false;\n }\n return true;\n }\n}\n" + }, + "src/misc/libraries/BitmapLib.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\n/// @title BitmapLib\nlibrary BitmapLib {\n function setBit(uint128 bitmap, uint128 index, bool isTrue) internal pure returns (uint128) {\n if (isTrue) {\n return bitmap | (uint128(1) << index);\n }\n\n return bitmap & ~(uint128(1) << index);\n }\n\n function getBit(uint128 bitmap, uint128 index) internal pure returns (bool) {\n uint128 bitAtIndex = uint128(bitmap & (1 << index));\n return bitAtIndex != 0;\n }\n}\n" + }, + "src/misc/libraries/BytesLib.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\n/// @title Bytes Lib\n/// @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity.\n/// The library lets you concatenate, slice and type cast bytes arrays both in memory and storage.\n/// @author Modified from Solidity Bytes Arrays Utils v0.8.0\nlibrary BytesLib {\n error SliceOverflow();\n error SliceOutOfBounds();\n\n function sliceZeroPadded(bytes memory _bytes, uint256 _start, uint256 _length)\n internal\n pure\n returns (bytes memory)\n {\n require(_length + 31 >= _length, SliceOverflow());\n\n bytes memory tempBytes;\n\n assembly {\n switch iszero(_length)\n case 0 {\n // Get a location of some free memory and store it in tempBytes as\n // Solidity does for memory variables.\n tempBytes := mload(0x40)\n\n // The first word of the slice result is potentially a partial\n // word read from the original array. To read it, we calculate\n // the length of that partial word and start copying that many\n // bytes into the array. The first word we copy will start with\n // data we don't care about, but the last `lengthmod` bytes will\n // land at the beginning of the contents of the new array. When\n // we're done copying, we overwrite the full first word with\n // the actual length of the slice.\n let lengthmod := and(_length, 31)\n\n // The multiplication in the next line is necessary\n // because when slicing multiples of 32 bytes (lengthmod == 0)\n // the following copy loop was copying the origin's length\n // and then ending prematurely not copying everything it should.\n let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))\n let end := add(mc, _length)\n\n for {\n // The multiplication in the next line has the same exact purpose\n // as the one above.\n let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)\n } lt(mc, end) {\n mc := add(mc, 0x20)\n cc := add(cc, 0x20)\n } { mstore(mc, mload(cc)) }\n\n mstore(tempBytes, _length)\n\n //update free-memory pointer\n //allocating the array padded to 32 bytes like the compiler does now\n mstore(0x40, and(add(mc, 31), not(31)))\n }\n //if we want a zero-length slice let's just return a zero-length array\n default {\n tempBytes := mload(0x40)\n //zero out the 32 bytes slice we are about to return\n //we need to do it because Solidity does not garbage collect\n mstore(tempBytes, 0)\n\n mstore(0x40, add(tempBytes, 0x20))\n }\n }\n\n return tempBytes;\n }\n\n function slice(bytes memory _bytes, uint256 _start, uint256 _length) internal pure returns (bytes memory) {\n require(_bytes.length >= _start + _length, SliceOutOfBounds());\n return sliceZeroPadded(_bytes, _start, _length);\n }\n\n function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) {\n require(_bytes.length >= _start + 20, SliceOutOfBounds());\n address tempAddress;\n\n assembly {\n tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000)\n }\n\n return tempAddress;\n }\n\n function toUint8(bytes memory _bytes, uint256 _start) internal pure returns (uint8) {\n require(_bytes.length >= _start + 1, SliceOutOfBounds());\n uint8 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x1), _start))\n }\n\n return tempUint;\n }\n\n function toUint16(bytes memory _bytes, uint256 _start) internal pure returns (uint16) {\n require(_bytes.length >= _start + 2, SliceOutOfBounds());\n uint16 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x2), _start))\n }\n\n return tempUint;\n }\n\n function toUint32(bytes memory _bytes, uint256 _start) internal pure returns (uint32) {\n require(_bytes.length >= _start + 4, SliceOutOfBounds());\n uint32 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x4), _start))\n }\n\n return tempUint;\n }\n\n function toUint64(bytes memory _bytes, uint256 _start) internal pure returns (uint64) {\n require(_bytes.length >= _start + 8, SliceOutOfBounds());\n uint64 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x8), _start))\n }\n\n return tempUint;\n }\n\n function toUint128(bytes memory _bytes, uint256 _start) internal pure returns (uint128) {\n require(_bytes.length >= _start + 16, SliceOutOfBounds());\n uint128 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x10), _start))\n }\n\n return tempUint;\n }\n\n function toUint256(bytes memory _bytes, uint256 _start) internal pure returns (uint256) {\n require(_bytes.length >= _start + 32, SliceOutOfBounds());\n uint256 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x20), _start))\n }\n\n return tempUint;\n }\n\n function toBytes32(bytes memory _bytes, uint256 _start) internal pure returns (bytes32) {\n require(_bytes.length >= _start + 32, SliceOutOfBounds());\n bytes32 tempBytes32;\n\n assembly {\n tempBytes32 := mload(add(add(_bytes, 0x20), _start))\n }\n\n return tempBytes32;\n }\n\n function toBytes16(bytes memory _bytes, uint256 _start) internal pure returns (bytes16) {\n require(_bytes.length >= _start + 16, SliceOutOfBounds());\n bytes16 tempBytes16;\n\n assembly {\n tempBytes16 := mload(add(add(_bytes, 0x20), _start))\n }\n\n return tempBytes16;\n }\n\n function toBool(bytes memory _bytes, uint256 _start) internal pure returns (bool) {\n require(_bytes.length > _start, SliceOutOfBounds());\n return _bytes[_start] != 0;\n }\n}\n" + }, + "src/misc/libraries/CastLib.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\n/// @title CastLib\nlibrary CastLib {\n function toAddressLeftPadded(bytes32 addr) internal pure returns (address) {\n require(bytes12(addr) == 0, \"First 12 bytes should be zero\");\n return address(uint160(uint256(addr)));\n }\n\n function toBytes32LeftPadded(address addr) internal pure returns (bytes32) {\n return bytes32(uint256(uint160(addr)));\n }\n\n function toAddress(bytes32 addr) internal pure returns (address) {\n require(uint96(uint256(addr)) == 0, \"Input should be 20 bytes\");\n return address(bytes20(addr));\n }\n\n function toString(address addr) internal pure returns (string memory) {\n return string(abi.encodePacked(addr));\n }\n\n function toBytes32(address addr) internal pure returns (bytes32) {\n return bytes32(bytes20(addr));\n }\n\n /// @dev Adds zero padding\n function toBytes32(string memory source) internal pure returns (bytes32) {\n return bytes32(bytes(source));\n }\n\n /// @dev Removes zero padding\n function bytes128ToString(bytes memory _bytes128) internal pure returns (string memory) {\n require(_bytes128.length == 128, \"Input should be 128 bytes\");\n\n uint8 i = 0;\n while (i < 128 && _bytes128[i] != 0) {\n i++;\n }\n\n bytes memory bytesArray = new bytes(i);\n\n for (uint8 j; j < i; j++) {\n bytesArray[j] = _bytes128[j];\n }\n\n return string(bytesArray);\n }\n\n function toString(bytes32 _bytes32) internal pure returns (string memory) {\n uint8 i = 0;\n while (i < 32 && _bytes32[i] != 0) {\n i++;\n }\n bytes memory bytesArray = new bytes(i);\n for (i = 0; i < 32 && _bytes32[i] != 0; i++) {\n bytesArray[i] = _bytes32[i];\n }\n return string(bytesArray);\n }\n}\n" + }, + "src/misc/libraries/EIP712Lib.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\n/// @title EIP712 Lib\nlibrary EIP712Lib {\n // keccak256(\"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\")\n bytes32 public constant EIP712_DOMAIN_TYPEHASH = 0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f;\n\n function calculateDomainSeparator(bytes32 nameHash, bytes32 versionHash) internal view returns (bytes32) {\n return keccak256(abi.encode(EIP712_DOMAIN_TYPEHASH, nameHash, versionHash, block.chainid, address(this)));\n }\n}\n" + }, + "src/misc/libraries/MathLib.sol": { + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.28;\n\nlibrary MathLib {\n enum Rounding {\n Down, // Toward negative infinity\n Up, // Toward infinity\n Zero // Toward zero\n\n }\n\n error MulDiv_Overflow();\n error Uint8_Overflow();\n error Uint32_Overflow();\n error Uint64_Overflow();\n error Uint128_Overflow();\n error Int128_Overflow();\n\n uint256 public constant One27 = 10 ** 27;\n\n /// @notice Returns x^n with rounding precision of base\n ///\n /// @dev Source: https://github.com/makerdao/dss/blob/fa4f6630afb0624d04a003e920b0d71a00331d98/src/jug.sol#L62\n ///\n /// @param x The base value which should be exponentiated\n /// @param n The exponent\n /// @param base The scaling base, typically used for fix-point calculations\n function rpow(uint256 x, uint256 n, uint256 base) public pure returns (uint256 z) {\n assembly {\n switch x\n case 0 {\n switch n\n case 0 { z := base }\n default { z := 0 }\n }\n default {\n switch mod(n, 2)\n case 0 { z := base }\n default { z := x }\n let half := div(base, 2) // for rounding.\n for { n := div(n, 2) } n { n := div(n, 2) } {\n let xx := mul(x, x)\n if iszero(eq(div(xx, x), x)) { revert(0, 0) }\n let xxRound := add(xx, half)\n if lt(xxRound, xx) { revert(0, 0) }\n x := div(xxRound, base)\n if mod(n, 2) {\n let zx := mul(z, x)\n if and(iszero(iszero(x)), iszero(eq(div(zx, x), z))) { revert(0, 0) }\n let zxRound := add(zx, half)\n if lt(zxRound, zx) { revert(0, 0) }\n z := div(zxRound, base)\n }\n }\n }\n }\n }\n\n /// @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or\n /// denominator == 0\n /// @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\n /// with further edits by Uniswap Labs also under MIT license.\n // slither-disable-start divide-before-multiply\n function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {\n unchecked {\n // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\n // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\n // variables such that product = prod1 * 2^256 + prod0.\n uint256 prod0; // Least significant 256 bits of the product\n uint256 prod1; // Most significant 256 bits of the product\n assembly {\n let mm := mulmod(x, y, not(0))\n prod0 := mul(x, y)\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n }\n\n // Handle non-overflow cases, 256 by 256 division.\n if (prod1 == 0) {\n // Solidity will revert if denominator == 0, unlike the div opcode on its own.\n // The surrounding unchecked block does not change this fact.\n // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.\n return prod0 / denominator;\n }\n\n // Make sure the result is less than 2^256. Also prevents denominator == 0.\n require(denominator > prod1, MulDiv_Overflow());\n\n ///////////////////////////////////////////////\n // 512 by 256 division.\n ///////////////////////////////////////////////\n\n // Make division exact by subtracting the remainder from [prod1 prod0].\n uint256 remainder;\n assembly {\n // Compute remainder using mulmod.\n remainder := mulmod(x, y, denominator)\n\n // Subtract 256 bit number from 512 bit number.\n prod1 := sub(prod1, gt(remainder, prod0))\n prod0 := sub(prod0, remainder)\n }\n\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator.\n // Always >= 1.\n // See https://cs.stackexchange.com/q/138556/92363.\n\n // Does not overflow because the denominator cannot be zero at this stage in the function.\n uint256 twos = denominator & (~denominator + 1);\n assembly {\n // Divide denominator by twos.\n denominator := div(denominator, twos)\n\n // Divide [prod1 prod0] by twos.\n prod0 := div(prod0, twos)\n\n // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\n twos := add(div(sub(0, twos), twos), 1)\n }\n\n // Shift in bits from prod1 into prod0.\n prod0 |= prod1 * twos;\n\n // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\n // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\n // four bits. That is, denominator * inv = 1 mod 2^4.\n uint256 inverse = (3 * denominator) ^ 2;\n\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also\n // works\n // in modular arithmetic, doubling the correct bits in each step.\n inverse *= 2 - denominator * inverse; // inverse mod 2^8\n inverse *= 2 - denominator * inverse; // inverse mod 2^16\n inverse *= 2 - denominator * inverse; // inverse mod 2^32\n inverse *= 2 - denominator * inverse; // inverse mod 2^64\n inverse *= 2 - denominator * inverse; // inverse mod 2^128\n inverse *= 2 - denominator * inverse; // inverse mod 2^256\n\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\n // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\n // is no longer required.\n result = prod0 * inverse;\n return result;\n }\n }\n // slither-disable-end divide-before-multiply\n\n /// @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\n function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {\n uint256 result = mulDiv(x, y, denominator);\n if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\n result += 1;\n }\n return result;\n }\n\n /// @notice Safe type conversion from uint256 to uint8.\n function toUint8(uint256 value) internal pure returns (uint8) {\n require(value <= type(uint8).max, Uint8_Overflow());\n return uint8(value);\n }\n\n function toUint32(uint256 value) internal pure returns (uint32) {\n require(value <= type(uint32).max, Uint32_Overflow());\n return uint32(value);\n }\n\n function toUint64(uint256 value) internal pure returns (uint64) {\n require(value <= type(uint64).max, Uint64_Overflow());\n return uint64(value);\n }\n\n /// @notice Safe type conversion from uint256 to uint128.\n function toUint128(uint256 value) internal pure returns (uint128) {\n require(value <= type(uint128).max, Uint128_Overflow());\n return uint128(value);\n }\n\n /// @notice Returns the smallest of two numbers.\n function min(uint256 a, uint256 b) internal pure returns (uint256) {\n return a > b ? b : a;\n }\n\n /// @notice Returns the largest of two numbers.\n function max(uint256 a, uint256 b) internal pure returns (uint256) {\n return a > b ? a : b;\n }\n}\n" + }, + "src/misc/libraries/SafeTransferLib.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IERC20} from \"src/misc/interfaces/IERC20.sol\";\n\n/// @title Safe Transfer Lib\n/// @author Modified from Uniswap v3 Periphery (libraries/TransferHelper.sol)\nlibrary SafeTransferLib {\n error NoCode();\n error SafeTransferFromFailed();\n error SafeTransferFailed();\n error SafeApproveFailed();\n error SafeTransferEthFailed();\n\n /// @notice Transfers tokens from the targeted address to the given destination\n /// @notice Errors if transfer fails\n /// @param token The contract address of the token to be transferred\n /// @param from The originating address from which the tokens will be transferred\n /// @param to The destination address of the transfer\n /// @param value The amount to be transferred\n function safeTransferFrom(address token, address from, address to, uint256 value) internal {\n require(address(token).code.length > 0, NoCode());\n\n (bool success, bytes memory data) = token.call(abi.encodeCall(IERC20.transferFrom, (from, to, value)));\n require(success && (data.length == 0 || abi.decode(data, (bool))), SafeTransferFromFailed());\n }\n\n /// @notice Transfers tokens from msg.sender to a recipient\n /// @dev Errors if transfer fails\n /// @param token The contract address of the token which will be transferred\n /// @param to The recipient of the transfer\n /// @param value The value of the transfer\n function safeTransfer(address token, address to, uint256 value) internal {\n require(address(token).code.length > 0, NoCode());\n\n (bool success, bytes memory data) = token.call(abi.encodeCall(IERC20.transfer, (to, value)));\n require(success && (data.length == 0 || abi.decode(data, (bool))), SafeTransferFailed());\n }\n\n /// @notice Approves the stipulated contract to spend the given allowance in the given token\n /// @dev Errors if approval fails\n /// @param token The contract address of the token to be approved\n /// @param to The target of the approval\n /// @param value The amount of the given token the target will be allowed to spend\n function safeApprove(address token, address to, uint256 value) internal {\n require(address(token).code.length > 0, NoCode());\n\n (bool success, bytes memory data) = token.call(abi.encodeCall(IERC20.approve, (to, value)));\n require(success && (data.length == 0 || abi.decode(data, (bool))), SafeApproveFailed());\n }\n\n /// @notice Transfers ETH to the recipient address\n /// @dev Fails with `STE`\n /// @dev Make sure that method that is using this function is protected from reentrancy\n /// @param to The destination of the transfer\n /// @param value The value to be transferred\n function safeTransferETH(address to, uint256 value) internal {\n (bool success,) = to.call{value: value}(new bytes(0));\n require(success, SafeTransferEthFailed());\n }\n}\n" + }, + "src/misc/libraries/SignatureLib.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\ninterface IERC1271 {\n function isValidSignature(bytes32, bytes memory) external view returns (bytes4);\n}\n\n/// @title Signature Lib\nlibrary SignatureLib {\n error InvalidSigner();\n\n function isValidSignature(address signer, bytes32 digest, bytes memory signature)\n internal\n view\n returns (bool valid)\n {\n require(signer != address(0), InvalidSigner());\n\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n if (signer == ecrecover(digest, v, r, s)) {\n return true;\n }\n }\n\n if (signer.code.length > 0) {\n (bool success, bytes memory result) =\n signer.staticcall(abi.encodeCall(IERC1271.isValidSignature, (digest, signature)));\n valid =\n (success && result.length == 32 && abi.decode(result, (bytes4)) == IERC1271.isValidSignature.selector);\n }\n }\n}\n" + }, + "src/misc/libraries/StringLib.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nlibrary StringLib {\n function isEmpty(string memory value) internal pure returns (bool) {\n return bytes(value).length == 0;\n }\n}\n" + }, + "src/misc/libraries/TransientArrayLib.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {TransientStorageLib} from \"src/misc/libraries/TransientStorageLib.sol\";\n\n/// @title TransientArrayLib\nlibrary TransientArrayLib {\n using TransientStorageLib for bytes32;\n\n function push(bytes32 key, bytes32 value) internal {\n bytes32 lengthSlot = keccak256(abi.encodePacked(key, type(uint256).max));\n uint256 length_ = lengthSlot.tloadUint256();\n lengthSlot.tstore(length_ + 1);\n\n bytes32 slot = keccak256(abi.encodePacked(key, length_));\n slot.tstore(value);\n }\n\n function getBytes32(bytes32 key) internal view returns (bytes32[] memory) {\n uint256 length_ = length(key);\n\n bytes32[] memory data = new bytes32[](length_);\n for (uint256 i = 0; i < length_; i++) {\n bytes32 slot = keccak256(abi.encodePacked(key, i));\n data[i] = slot.tloadBytes32();\n }\n\n return data;\n }\n\n function length(bytes32 key) internal view returns (uint256) {\n return keccak256(abi.encodePacked(key, type(uint256).max)).tloadUint256();\n }\n\n function clear(bytes32 key) internal {\n bytes32 lengthSlot = keccak256(abi.encodePacked(key, type(uint256).max));\n lengthSlot.tstore(uint256(0));\n }\n}\n" + }, + "src/misc/libraries/TransientBytesLib.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\nimport {TransientStorageLib} from \"src/misc/libraries/TransientStorageLib.sol\";\n\n/// @title TransientBytesLib\nlibrary TransientBytesLib {\n using TransientStorageLib for bytes32;\n using BytesLib for bytes;\n\n function append(bytes32 key, bytes memory value) internal {\n bytes32 lengthSlot = keccak256(abi.encodePacked(key, type(uint256).max));\n uint256 prevLength = lengthSlot.tloadUint256();\n\n uint256 startChunk = prevLength / 32;\n uint256 offset = prevLength % 32;\n\n lengthSlot.tstore(prevLength + value.length);\n\n bytes32 joinSlot = keccak256(abi.encodePacked(key, startChunk));\n bytes memory firstPart = abi.encodePacked(joinSlot.tloadBytes32()).sliceZeroPadded(0, offset);\n bytes memory secondPart = value.sliceZeroPadded(0, 32 - offset);\n joinSlot.tstore(bytes32(bytes.concat(firstPart, secondPart)));\n\n uint256 valueOffset = 32 - offset;\n uint256 chunkIndex = startChunk + 1;\n for (; valueOffset < value.length; chunkIndex++) {\n bytes32 slot = keccak256(abi.encodePacked(key, chunkIndex));\n slot.tstore(bytes32(value.sliceZeroPadded(valueOffset, 32)));\n valueOffset += 32;\n }\n }\n\n function get(bytes32 key) internal view returns (bytes memory) {\n bytes memory data;\n uint256 length = keccak256(abi.encodePacked(key, type(uint256).max)).tloadUint256();\n if (length == 0) return data;\n\n uint256 chunks = length / 32 + 1;\n for (uint256 i = 0; i < chunks; i++) {\n bytes32 slot = keccak256(abi.encodePacked(key, i));\n data = bytes.concat(data, slot.tloadBytes32());\n }\n\n return data.slice(0, length);\n }\n\n function clear(bytes32 key) internal {\n bytes32 lengthSlot = keccak256(abi.encodePacked(key, type(uint256).max));\n lengthSlot.tstore(uint256(0));\n }\n}\n" + }, + "src/misc/libraries/TransientStorageLib.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\n/// @title TransientStorageLib\nlibrary TransientStorageLib {\n function tstore(bytes32 slot, address value) internal {\n assembly (\"memory-safe\") {\n tstore(slot, value)\n }\n }\n\n function tstore(bytes32 slot, uint256 value) internal {\n assembly (\"memory-safe\") {\n tstore(slot, value)\n }\n }\n\n function tstore(bytes32 slot, bytes32 value) internal {\n assembly (\"memory-safe\") {\n tstore(slot, value)\n }\n }\n\n function tstore(bytes32 slot, bool value) internal {\n assembly (\"memory-safe\") {\n tstore(slot, value)\n }\n }\n\n function tloadAddress(bytes32 slot) internal view returns (address value) {\n assembly (\"memory-safe\") {\n value := tload(slot)\n }\n }\n\n function tloadUint128(bytes32 slot) internal view returns (uint128 value) {\n assembly (\"memory-safe\") {\n value := tload(slot)\n }\n }\n\n function tloadUint256(bytes32 slot) internal view returns (uint256 value) {\n assembly (\"memory-safe\") {\n value := tload(slot)\n }\n }\n\n function tloadBytes32(bytes32 slot) internal view returns (bytes32 value) {\n assembly (\"memory-safe\") {\n value := tload(slot)\n }\n }\n\n function tloadBool(bytes32 slot) internal view returns (bool value) {\n assembly (\"memory-safe\") {\n value := tload(slot)\n }\n }\n}\n" + }, + "src/misc/types/D18.sol": { + "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.28;\n\n// Small library to handle fixed point number operations with 18 decimals with static typing support.\n\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\n\ntype D18 is uint128;\n\nusing MathLib for uint256;\n\n/// @dev add two D18 types\nfunction add(D18 d1, D18 d2) pure returns (D18) {\n return D18.wrap(D18.unwrap(d1) + D18.unwrap(d2));\n}\n\n/// @dev substract two D18 types\nfunction sub(D18 d1, D18 d2) pure returns (D18) {\n return D18.wrap(D18.unwrap(d1) - D18.unwrap(d2));\n}\n\n/// @dev Divides one D18 by another one while retaining precision:\n/// - nominator (decimal): 50e18\n/// - denominator (decimal): 2e19\n/// - result (decimal): 25e17\nfunction divD18(D18 d1, D18 d2) pure returns (D18) {\n return D18.wrap(MathLib.mulDiv(D18.unwrap(d1), 1e18, D18.unwrap(d2)).toUint128());\n}\n\n/// @dev Multiplies one D18 with another one while retaining precision:\n/// - value1 (decimal): 50e18\n/// - value2 (decimal): 2e19\n/// - result (decimal): 100e19\nfunction mulD18(D18 d1, D18 d2) pure returns (D18) {\n return D18.wrap(MathLib.mulDiv(D18.unwrap(d1), D18.unwrap(d2), 1e18).toUint128());\n}\n\n/// @dev sugar for getting the inner representation of a D18\nfunction inner(D18 d1) pure returns (uint128) {\n return D18.unwrap(d1);\n}\n\n/// @dev Returns the reciprocal of a D18 decimal, i.e. 1 / d.\n/// Example: if d = 2.0 (2e18 internally), reciprocal(d) = 0.5 (5e17 internally).\nfunction reciprocal(D18 d) pure returns (D18) {\n uint128 val = D18.unwrap(d);\n require(val != 0, \"D18/division-by-zero\");\n return d18(1e18, val);\n}\n\n/// @dev Multiplies a decimal by an integer. i.e:\n/// - d (decimal): 1_500_000_000_000_000_000\n/// - value (integer): 4_000_000_000_000_000_000\n/// - result (integer): 6_000_000_000_000_000_000\nfunction mulUint128(D18 d, uint128 value, MathLib.Rounding rounding) pure returns (uint128) {\n return MathLib.mulDiv(D18.unwrap(d), value, 1e18, rounding).toUint128();\n}\n\n/// @dev Multiplies a decimal by an integer. i.e:\n/// - d (decimal): 1_500_000_000_000_000_000\n/// - value (integer): 4_000_000_000_000_000_000\n/// - result (integer): 6_000_000_000_000_000_000\nfunction mulUint256(D18 d, uint256 value, MathLib.Rounding rounding) pure returns (uint256) {\n return MathLib.mulDiv(D18.unwrap(d), value, 1e18, rounding);\n}\n\n/// @dev Divides an integer by a decimal, i.e.\n/// @dev Same as mulDiv for integers, i.e:\n/// - d (decimal): 2_000_000_000_000_000_000\n/// - value (integer): 100_000_000_000_000_000_000\n/// - result (integer): 50_000_000_000_000_000_000\nfunction reciprocalMulUint128(D18 d, uint128 value, MathLib.Rounding rounding) pure returns (uint128) {\n return MathLib.mulDiv(value, 1e18, d.inner(), rounding).toUint128();\n}\n\n/// @dev Divides an integer by a decimal, i.e.\n/// @dev Same as mulDiv for integers, i.e:\n/// - d (decimal): 2_000_000_000_000_000_000\n/// - value (integer): 100_000_000_000_000_000_000\n/// - result (integer): 50_000_000_000_000_000_000\nfunction reciprocalMulUint256(D18 d, uint256 value, MathLib.Rounding rounding) pure returns (uint256) {\n return MathLib.mulDiv(value, 1e18, d.inner(), rounding);\n}\n\n/// @dev Easy way to construct a decimal number\nfunction d18(uint128 value) pure returns (D18) {\n return D18.wrap(value);\n}\n\n/// @dev Easy way to construct a decimal number\nfunction d18(uint128 num, uint128 den) pure returns (D18) {\n return D18.wrap(MathLib.mulDiv(num, 1e18, den).toUint128());\n}\n\nfunction eq(D18 a, D18 b) pure returns (bool) {\n return D18.unwrap(a) == D18.unwrap(b);\n}\n\nfunction raw(D18 d) pure returns (uint128) {\n return D18.unwrap(d);\n}\n\nusing {\n add as +,\n sub as -,\n divD18 as /,\n inner,\n eq,\n mulD18 as *,\n mulUint128,\n mulUint256,\n reciprocalMulUint128,\n reciprocalMulUint256,\n reciprocal,\n raw\n} for D18 global;\n" + }, + "src/vaults/AsyncRequestManager.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\nimport {D18, d18} from \"src/misc/types/D18.sol\";\n\nimport {MessageLib} from \"src/common/libraries/MessageLib.sol\";\nimport {IVaultMessageSender} from \"src/common/interfaces/IGatewaySenders.sol\";\nimport {IRequestManagerGatewayHandler} from \"src/common/interfaces/IGatewayHandlers.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {PricingLib} from \"src/common/libraries/PricingLib.sol\";\n\nimport {IPoolManager, VaultDetails} from \"src/vaults/interfaces/IPoolManager.sol\";\nimport {IBalanceSheet} from \"src/vaults/interfaces/IBalanceSheet.sol\";\nimport {IAsyncRequestManager, AsyncInvestmentState} from \"src/vaults/interfaces/investments/IAsyncRequestManager.sol\";\nimport {IAsyncRedeemManager} from \"src/vaults/interfaces/investments/IAsyncRedeemManager.sol\";\nimport {IAsyncDepositManager} from \"src/vaults/interfaces/investments/IAsyncDepositManager.sol\";\nimport {IDepositManager} from \"src/vaults/interfaces/investments/IDepositManager.sol\";\nimport {IRedeemManager} from \"src/vaults/interfaces/investments/IRedeemManager.sol\";\nimport {IBaseRequestManager} from \"src/vaults/interfaces/investments/IBaseRequestManager.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\nimport {IAsyncVault, IBaseVault, IAsyncRedeemVault, VaultKind} from \"src/vaults/interfaces/IBaseVaults.sol\";\nimport {BaseRequestManager} from \"src/vaults/BaseRequestManager.sol\";\nimport {IPoolEscrowProvider} from \"src/vaults/interfaces/factories/IPoolEscrowFactory.sol\";\nimport {IEscrow} from \"src/vaults/interfaces/IEscrow.sol\";\nimport {ESCROW_HOOK_ID} from \"src/common/interfaces/IHook.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\n\n/// @title Investment Manager\n/// @notice This is the main contract vaults interact with for\n/// both incoming and outgoing investment transactions.\ncontract AsyncRequestManager is BaseRequestManager, IAsyncRequestManager {\n using CastLib for *;\n using MessageLib for *;\n using BytesLib for bytes;\n using MathLib for uint256;\n\n IVaultMessageSender public sender;\n IBalanceSheet public balanceSheet;\n\n mapping(IBaseVault vault => mapping(address investor => AsyncInvestmentState)) public investments;\n\n constructor(IEscrow globalEscrow_, address root_, address deployer)\n BaseRequestManager(globalEscrow_, root_, deployer)\n {}\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n function file(bytes32 what, address data) external override(IBaseRequestManager, BaseRequestManager) auth {\n if (what == \"sender\") sender = IVaultMessageSender(data);\n else if (what == \"poolManager\") poolManager = IPoolManager(data);\n else if (what == \"balanceSheet\") balanceSheet = IBalanceSheet(data);\n else if (what == \"poolEscrowProvider\") poolEscrowProvider = IPoolEscrowProvider(data);\n else revert FileUnrecognizedParam();\n emit File(what, data);\n }\n\n //----------------------------------------------------------------------------------------------\n // Async investment handlers\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IAsyncDepositManager\n function requestDeposit(IBaseVault vault_, uint256 assets, address controller, address, address)\n public\n auth\n returns (bool)\n {\n uint128 assets_ = assets.toUint128();\n require(assets_ != 0, ZeroAmountNotAllowed());\n\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n PoolId poolId = vault_.poolId();\n ShareClassId scId = vault_.scId();\n\n require(poolManager.isLinked(poolId, scId, vaultDetails.asset, vault_), AssetNotAllowed());\n\n require(_canTransfer(vault_, address(0), controller, convertToShares(vault_, assets_)), TransferNotAllowed());\n\n AsyncInvestmentState storage state = investments[vault_][controller];\n require(state.pendingCancelDepositRequest != true, CancellationIsPending());\n\n state.pendingDepositRequest += assets_;\n sender.sendDepositRequest(poolId, scId, controller.toBytes32(), vaultDetails.assetId, assets_);\n\n return true;\n }\n\n /// @inheritdoc IAsyncRedeemManager\n function requestRedeem(IBaseVault vault_, uint256 shares, address controller, address owner, address)\n public\n auth\n returns (bool)\n {\n uint128 shares_ = shares.toUint128();\n require(shares_ != 0, ZeroAmountNotAllowed());\n\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n PoolId poolId = vault_.poolId();\n ShareClassId scId = vault_.scId();\n\n require(poolManager.isLinked(poolId, scId, vaultDetails.asset, vault_), AssetNotAllowed());\n\n require(\n _canTransfer(vault_, owner, ESCROW_HOOK_ID, shares)\n && _canTransfer(vault_, controller, ESCROW_HOOK_ID, shares),\n TransferNotAllowed()\n );\n\n AsyncInvestmentState storage state = investments[vault_][controller];\n require(state.pendingCancelRedeemRequest != true, CancellationIsPending());\n\n state.pendingRedeemRequest = state.pendingRedeemRequest + shares_;\n sender.sendRedeemRequest(poolId, scId, controller.toBytes32(), vaultDetails.assetId, shares_);\n\n return true;\n }\n\n /// @inheritdoc IAsyncDepositManager\n function cancelDepositRequest(IBaseVault vault_, address controller, address) public auth {\n AsyncInvestmentState storage state = investments[vault_][controller];\n require(state.pendingDepositRequest > 0, NoPendingRequest());\n require(state.pendingCancelDepositRequest != true, CancellationIsPending());\n state.pendingCancelDepositRequest = true;\n\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n\n sender.sendCancelDepositRequest(vault_.poolId(), vault_.scId(), controller.toBytes32(), vaultDetails.assetId);\n }\n\n /// @inheritdoc IAsyncRedeemManager\n function cancelRedeemRequest(IBaseVault vault_, address controller, address) public auth {\n uint256 approximateSharesPayout = pendingRedeemRequest(vault_, controller);\n require(approximateSharesPayout > 0, NoPendingRequest());\n require(_canTransfer(vault_, address(0), controller, approximateSharesPayout), TransferNotAllowed());\n\n AsyncInvestmentState storage state = investments[vault_][controller];\n require(state.pendingCancelRedeemRequest != true, CancellationIsPending());\n state.pendingCancelRedeemRequest = true;\n\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n\n sender.sendCancelRedeemRequest(vault_.poolId(), vault_.scId(), controller.toBytes32(), vaultDetails.assetId);\n }\n\n //----------------------------------------------------------------------------------------------\n // Gateway handlers\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IRequestManagerGatewayHandler\n function approvedDeposits(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n uint128 assetAmount,\n D18 pricePoolPerAsset\n ) external auth {\n (address asset, uint256 tokenId) = poolManager.idToAsset(assetId);\n\n // Note deposit and transfer from global escrow into the pool escrow,\n // to make assets available for managers of the balance sheet\n balanceSheet.overridePricePoolPerAsset(poolId, scId, assetId, pricePoolPerAsset);\n balanceSheet.noteDeposit(poolId, scId, asset, tokenId, address(globalEscrow), assetAmount);\n\n address poolEscrow = address(poolEscrowProvider.escrow(poolId));\n globalEscrow.authTransferTo(asset, tokenId, poolEscrow, assetAmount);\n }\n\n /// @inheritdoc IRequestManagerGatewayHandler\n function issuedShares(PoolId poolId, ShareClassId scId, uint128 shareAmount, D18 pricePoolPerShare) external auth {\n balanceSheet.overridePricePoolPerShare(poolId, scId, pricePoolPerShare);\n balanceSheet.issue(poolId, scId, address(globalEscrow), shareAmount);\n }\n\n /// @inheritdoc IRequestManagerGatewayHandler\n function revokedShares(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n uint128 assetAmount,\n uint128 shareAmount,\n D18 pricePoolPerShare\n ) external auth {\n // Lock assets to ensure they are not withdrawn and are available for the redeeming user\n (address asset, uint256 tokenId) = poolManager.idToAsset(assetId);\n poolEscrowProvider.escrow(poolId).reserveIncrease(scId, asset, tokenId, assetAmount);\n\n balanceSheet.overridePricePoolPerShare(poolId, scId, pricePoolPerShare);\n balanceSheet.revoke(poolId, scId, address(globalEscrow), shareAmount);\n }\n\n /// @inheritdoc IRequestManagerGatewayHandler\n function fulfillDepositRequest(\n PoolId poolId,\n ShareClassId scId,\n address user,\n AssetId assetId,\n uint128 assets,\n uint128 shares\n ) public auth {\n IAsyncVault vault_ = IAsyncVault(address(vault[poolId][scId][assetId]));\n\n AsyncInvestmentState storage state = investments[vault_][user];\n require(state.pendingDepositRequest != 0, NoPendingRequest());\n state.depositPrice = _calculatePriceAssetPerShare(\n vault_, state.maxMint + shares, _maxDeposit(vault_, user) + assets, MathLib.Rounding.Down\n );\n state.maxMint = state.maxMint + shares;\n state.pendingDepositRequest = state.pendingDepositRequest > assets ? state.pendingDepositRequest - assets : 0;\n\n if (state.pendingDepositRequest == 0) delete state.pendingCancelDepositRequest;\n\n vault_.onDepositClaimable(user, assets, shares);\n }\n\n /// @inheritdoc IRequestManagerGatewayHandler\n function fulfillRedeemRequest(\n PoolId poolId,\n ShareClassId scId,\n address user,\n AssetId assetId,\n uint128 assets,\n uint128 shares\n ) public auth {\n IAsyncRedeemVault vault_ = IAsyncRedeemVault(address(vault[poolId][scId][assetId]));\n\n AsyncInvestmentState storage state = investments[vault_][user];\n require(state.pendingRedeemRequest != 0, NoPendingRequest());\n\n // Calculate new weighted average redeem price and update order book values\n state.redeemPrice = _calculatePriceAssetPerShare(\n vault_, ((maxRedeem(vault_, user)) + shares).toUint128(), state.maxWithdraw + assets, MathLib.Rounding.Down\n );\n state.maxWithdraw = state.maxWithdraw + assets;\n state.pendingRedeemRequest = state.pendingRedeemRequest > shares ? state.pendingRedeemRequest - shares : 0;\n\n if (state.pendingRedeemRequest == 0) delete state.pendingCancelRedeemRequest;\n\n vault_.onRedeemClaimable(user, assets, shares);\n }\n\n /// @inheritdoc IRequestManagerGatewayHandler\n function fulfillCancelDepositRequest(\n PoolId poolId,\n ShareClassId scId,\n address user,\n AssetId assetId,\n uint128 assets,\n uint128 fulfillment\n ) public auth {\n IAsyncVault vault_ = IAsyncVault(address(vault[poolId][scId][assetId]));\n\n AsyncInvestmentState storage state = investments[vault_][user];\n require(state.pendingCancelDepositRequest == true, NoPendingRequest());\n\n state.claimableCancelDepositRequest = state.claimableCancelDepositRequest + assets;\n state.pendingDepositRequest =\n state.pendingDepositRequest > fulfillment ? state.pendingDepositRequest - fulfillment : 0;\n\n if (state.pendingDepositRequest == 0) delete state.pendingCancelDepositRequest;\n\n vault_.onCancelDepositClaimable(user, assets);\n }\n\n /// @inheritdoc IRequestManagerGatewayHandler\n function fulfillCancelRedeemRequest(PoolId poolId, ShareClassId scId, address user, AssetId assetId, uint128 shares)\n public\n auth\n {\n IAsyncRedeemVault vault_ = IAsyncRedeemVault(address(vault[poolId][scId][assetId]));\n AsyncInvestmentState storage state = investments[vault_][user];\n require(state.pendingCancelRedeemRequest == true, NoPendingRequest());\n\n state.claimableCancelRedeemRequest = state.claimableCancelRedeemRequest + shares;\n state.pendingRedeemRequest = state.pendingRedeemRequest > shares ? state.pendingRedeemRequest - shares : 0;\n\n if (state.pendingRedeemRequest == 0) delete state.pendingCancelRedeemRequest;\n\n vault_.onCancelRedeemClaimable(user, shares);\n }\n\n //----------------------------------------------------------------------------------------------\n // Sync investment handlers\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IDepositManager\n function deposit(IBaseVault vault_, uint256 assets, address receiver, address controller)\n public\n auth\n returns (uint256 shares)\n {\n require(assets <= _maxDeposit(vault_, controller), ExceedsMaxDeposit());\n\n AsyncInvestmentState storage state = investments[vault_][controller];\n\n uint128 sharesUp = _assetToShareAmount(vault_, assets.toUint128(), state.depositPrice, MathLib.Rounding.Up);\n uint128 sharesDown = _assetToShareAmount(vault_, assets.toUint128(), state.depositPrice, MathLib.Rounding.Down);\n shares = uint256(sharesDown);\n _processDeposit(state, sharesUp, sharesDown, vault_, receiver);\n }\n\n /// @inheritdoc IDepositManager\n function mint(IBaseVault vault_, uint256 shares, address receiver, address controller)\n public\n auth\n returns (uint256 assets)\n {\n AsyncInvestmentState storage state = investments[vault_][controller];\n uint128 shares_ = shares.toUint128();\n\n assets = uint256(_shareToAssetAmount(vault_, shares_, state.depositPrice, MathLib.Rounding.Up));\n _processDeposit(state, shares_, shares_, vault_, receiver);\n }\n\n function _processDeposit(\n AsyncInvestmentState storage state,\n uint128 sharesUp,\n uint128 sharesDown,\n IBaseVault vault_,\n address receiver\n ) internal {\n require(sharesUp <= state.maxMint, ExceedsDepositLimits());\n state.maxMint = state.maxMint > sharesUp ? state.maxMint - sharesUp : 0;\n\n if (sharesDown > 0) {\n globalEscrow.authTransferTo(vault_.share(), receiver, sharesDown);\n }\n }\n\n /// @inheritdoc IRedeemManager\n function redeem(IBaseVault vault_, uint256 shares, address receiver, address controller)\n public\n auth\n returns (uint256 assets)\n {\n require(shares <= maxRedeem(vault_, controller), ExceedsMaxRedeem());\n\n AsyncInvestmentState storage state = investments[vault_][controller];\n\n uint128 assetsUp = _shareToAssetAmount(vault_, shares.toUint128(), state.redeemPrice, MathLib.Rounding.Up);\n uint128 assetsDown = _shareToAssetAmount(vault_, shares.toUint128(), state.redeemPrice, MathLib.Rounding.Down);\n _processRedeem(state, assetsUp, assetsDown, vault_, receiver, controller);\n assets = uint256(assetsDown);\n }\n\n /// @inheritdoc IRedeemManager\n function withdraw(IBaseVault vault_, uint256 assets, address receiver, address controller)\n public\n auth\n returns (uint256 shares)\n {\n AsyncInvestmentState storage state = investments[vault_][controller];\n uint128 assets_ = assets.toUint128();\n _processRedeem(state, assets_, assets_, vault_, receiver, controller);\n\n shares = uint256(_assetToShareAmount(vault_, assets_, state.redeemPrice, MathLib.Rounding.Up));\n }\n\n function _processRedeem(\n AsyncInvestmentState storage state,\n uint128 assetsUp,\n uint128 assetsDown,\n IBaseVault vault_,\n address receiver,\n address controller\n ) internal {\n if (controller != receiver) {\n require(\n _canTransfer(vault_, controller, receiver, convertToShares(vault_, assetsDown)), TransferNotAllowed()\n );\n }\n\n require(_canTransfer(vault_, receiver, address(0), convertToShares(vault_, assetsDown)), TransferNotAllowed());\n\n require(assetsUp <= state.maxWithdraw, ExceedsRedeemLimits());\n state.maxWithdraw = state.maxWithdraw > assetsUp ? state.maxWithdraw - assetsUp : 0;\n\n if (assetsDown > 0) {\n _withdraw(vault_, receiver, assetsDown);\n }\n }\n\n /// @dev Transfer funds from escrow to receiver and update holdings\n function _withdraw(IBaseVault vault_, address receiver, uint128 assets) internal {\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n\n PoolId poolId = vault_.poolId();\n ShareClassId scId = vault_.scId();\n\n poolEscrowProvider.escrow(poolId).reserveDecrease(scId, vaultDetails.asset, vaultDetails.tokenId, assets);\n balanceSheet.withdraw(poolId, scId, vaultDetails.asset, vaultDetails.tokenId, receiver, assets);\n }\n\n //----------------------------------------------------------------------------------------------\n // Cancellation claim handlers\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IAsyncDepositManager\n function claimCancelDepositRequest(IBaseVault vault_, address receiver, address controller)\n public\n auth\n returns (uint256 assets)\n {\n AsyncInvestmentState storage state = investments[vault_][controller];\n assets = state.claimableCancelDepositRequest;\n state.claimableCancelDepositRequest = 0;\n uint256 shares = convertToShares(vault_, assets);\n\n if (controller != receiver) {\n require(_canTransfer(vault_, controller, receiver, shares), TransferNotAllowed());\n }\n require(_canTransfer(vault_, receiver, address(0), shares), TransferNotAllowed());\n\n if (assets > 0) {\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n globalEscrow.authTransferTo(vaultDetails.asset, vaultDetails.tokenId, receiver, assets);\n }\n }\n\n /// @inheritdoc IAsyncRedeemManager\n function claimCancelRedeemRequest(IBaseVault vault_, address receiver, address controller)\n public\n auth\n returns (uint256 shares)\n {\n AsyncInvestmentState storage state = investments[vault_][controller];\n shares = state.claimableCancelRedeemRequest;\n state.claimableCancelRedeemRequest = 0;\n\n if (shares > 0) {\n globalEscrow.authTransferTo(vault_.share(), receiver, shares);\n }\n }\n\n //----------------------------------------------------------------------------------------------\n // View methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IDepositManager\n function maxDeposit(IBaseVault vault_, address user) public view returns (uint256 assets) {\n if (!_canTransfer(vault_, ESCROW_HOOK_ID, user, 0)) {\n return 0;\n }\n assets = uint256(_maxDeposit(vault_, user));\n }\n\n function _maxDeposit(IBaseVault vault_, address user) internal view returns (uint128 assets) {\n AsyncInvestmentState memory state = investments[vault_][user];\n\n assets = _shareToAssetAmount(vault_, state.maxMint, state.depositPrice, MathLib.Rounding.Down);\n }\n\n /// @inheritdoc IDepositManager\n function maxMint(IBaseVault vault_, address user) public view returns (uint256 shares) {\n if (!_canTransfer(vault_, ESCROW_HOOK_ID, user, 0)) {\n return 0;\n }\n shares = uint256(investments[vault_][user].maxMint);\n }\n\n /// @inheritdoc IRedeemManager\n function maxWithdraw(IBaseVault vault_, address user) public view returns (uint256 assets) {\n if (!_canTransfer(vault_, user, address(0), 0)) return 0;\n assets = uint256(investments[vault_][user].maxWithdraw);\n }\n\n /// @inheritdoc IRedeemManager\n function maxRedeem(IBaseVault vault_, address user) public view returns (uint256 shares) {\n if (!_canTransfer(vault_, user, address(0), 0)) return 0;\n AsyncInvestmentState memory state = investments[vault_][user];\n\n shares = uint256(_assetToShareAmount(vault_, state.maxWithdraw, state.redeemPrice, MathLib.Rounding.Down));\n }\n\n /// @inheritdoc IAsyncDepositManager\n function pendingDepositRequest(IBaseVault vault_, address user) public view returns (uint256 assets) {\n assets = uint256(investments[vault_][user].pendingDepositRequest);\n }\n\n /// @inheritdoc IAsyncRedeemManager\n function pendingRedeemRequest(IBaseVault vault_, address user) public view returns (uint256 shares) {\n shares = uint256(investments[vault_][user].pendingRedeemRequest);\n }\n\n /// @inheritdoc IAsyncDepositManager\n function pendingCancelDepositRequest(IBaseVault vault_, address user) public view returns (bool isPending) {\n isPending = investments[vault_][user].pendingCancelDepositRequest;\n }\n\n /// @inheritdoc IAsyncRedeemManager\n function pendingCancelRedeemRequest(IBaseVault vault_, address user) public view returns (bool isPending) {\n isPending = investments[vault_][user].pendingCancelRedeemRequest;\n }\n\n /// @inheritdoc IAsyncDepositManager\n function claimableCancelDepositRequest(IBaseVault vault_, address user) public view returns (uint256 assets) {\n assets = investments[vault_][user].claimableCancelDepositRequest;\n }\n\n /// @inheritdoc IAsyncRedeemManager\n function claimableCancelRedeemRequest(IBaseVault vault_, address user) public view returns (uint256 shares) {\n shares = investments[vault_][user].claimableCancelRedeemRequest;\n }\n\n //----------------------------------------------------------------------------------------------\n // Helpers\n //----------------------------------------------------------------------------------------------\n\n /// @dev Checks transfer restrictions for the vault shares. Sender (from) and receiver (to) have to both pass\n /// the restrictions for a successful share transfer.\n function _canTransfer(IBaseVault vault_, address from, address to, uint256 value) internal view returns (bool) {\n IShareToken share = IShareToken(vault_.share());\n return share.checkTransferRestriction(from, to, value);\n }\n\n function _assetToShareAmount(\n IBaseVault vault_,\n uint128 assets,\n uint256 priceAssetPerShare,\n MathLib.Rounding rounding\n ) internal view returns (uint128 shares) {\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n address shareToken = vault_.share();\n\n return PricingLib.assetToShareAmount(\n shareToken, vaultDetails.asset, vaultDetails.tokenId, assets, d18(priceAssetPerShare.toUint128()), rounding\n );\n }\n\n function _shareToAssetAmount(\n IBaseVault vault_,\n uint128 shares,\n uint256 priceAssetPerShare,\n MathLib.Rounding rounding\n ) internal view returns (uint128 assets) {\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n address shareToken = vault_.share();\n\n return PricingLib.shareToAssetAmount(\n shareToken, shares, vaultDetails.asset, vaultDetails.tokenId, d18(priceAssetPerShare.toUint128()), rounding\n );\n }\n\n function _calculatePriceAssetPerShare(IBaseVault vault_, uint128 shares, uint128 assets, MathLib.Rounding rounding)\n internal\n view\n returns (uint256 price)\n {\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n address shareToken = vault_.share();\n\n return PricingLib.calculatePriceAssetPerShare(\n shareToken, shares, vaultDetails.asset, vaultDetails.tokenId, assets, rounding\n );\n }\n}\n" + }, + "src/vaults/AsyncVault.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport \"src/misc/interfaces/IERC7540.sol\";\nimport \"src/misc/interfaces/IERC7575.sol\";\nimport {SafeTransferLib} from \"src/misc/libraries/SafeTransferLib.sol\";\nimport {IERC20} from \"src/misc/interfaces/IERC20.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nimport {IAsyncRedeemVault, VaultKind} from \"src/vaults/interfaces/IBaseVaults.sol\";\nimport {BaseVault, BaseAsyncRedeemVault} from \"src/vaults/BaseVaults.sol\";\nimport {IAsyncVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\nimport {IAsyncRequestManager} from \"src/vaults/interfaces/investments/IAsyncRequestManager.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\n\n/// @title AsyncVault\n/// @notice Asynchronous Tokenized Vault standard implementation for Centrifuge pools\n///\n/// @dev Each vault issues shares of Centrifuge share class tokens as restricted ERC-20 tokens\n/// against asset deposits based on the current share price.\n///\n/// ERC-7540 is an extension of the ERC-4626 standard by 'requestDeposit' & 'requestRedeem' methods, where\n/// deposit and redeem orders are submitted to the pools to be included in the execution of the following epoch.\n/// After execution users can use the deposit, mint, redeem and withdraw functions to get their shares\n/// and/or assets from the pools.\ncontract AsyncVault is BaseAsyncRedeemVault, IAsyncVault {\n constructor(\n PoolId poolId_,\n ShareClassId scId_,\n address asset_,\n IShareToken token_,\n address root_,\n IAsyncRequestManager manager_\n ) BaseVault(poolId_, scId_, asset_, token_, root_, manager_) BaseAsyncRedeemVault(manager_) {}\n\n //----------------------------------------------------------------------------------------------\n // ERC-7540 deposit\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC7540Deposit\n function requestDeposit(uint256 assets, address controller, address owner) public returns (uint256) {\n require(owner == msg.sender || isOperator[owner][msg.sender], InvalidOwner());\n require(IERC20(asset).balanceOf(owner) >= assets, InsufficientBalance());\n\n require(asyncManager().requestDeposit(this, assets, controller, owner, msg.sender), RequestDepositFailed());\n SafeTransferLib.safeTransferFrom(asset, owner, address(manager.globalEscrow()), assets);\n\n emit DepositRequest(controller, owner, REQUEST_ID, msg.sender, assets);\n return REQUEST_ID;\n }\n\n /// @inheritdoc IERC7540Deposit\n function pendingDepositRequest(uint256, address controller) public view returns (uint256 pendingAssets) {\n pendingAssets = asyncManager().pendingDepositRequest(this, controller);\n }\n\n /// @inheritdoc IERC7540Deposit\n function claimableDepositRequest(uint256, address controller) external view returns (uint256 claimableAssets) {\n claimableAssets = maxDeposit(controller);\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-7887\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC7887Deposit\n function cancelDepositRequest(uint256, address controller) external {\n _validateController(controller);\n asyncManager().cancelDepositRequest(this, controller, msg.sender);\n emit CancelDepositRequest(controller, REQUEST_ID, msg.sender);\n }\n\n /// @inheritdoc IERC7887Deposit\n function pendingCancelDepositRequest(uint256, address controller) public view returns (bool isPending) {\n isPending = asyncManager().pendingCancelDepositRequest(this, controller);\n }\n\n /// @inheritdoc IERC7887Deposit\n function claimableCancelDepositRequest(uint256, address controller) public view returns (uint256 claimableAssets) {\n claimableAssets = asyncManager().claimableCancelDepositRequest(this, controller);\n }\n\n /// @inheritdoc IERC7887Deposit\n function claimCancelDepositRequest(uint256, address receiver, address controller)\n external\n returns (uint256 assets)\n {\n _validateController(controller);\n assets = asyncManager().claimCancelDepositRequest(this, receiver, controller);\n emit CancelDepositClaim(controller, receiver, REQUEST_ID, msg.sender, assets);\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-165\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC165\n function supportsInterface(bytes4 interfaceId) public pure override(BaseAsyncRedeemVault, IERC165) returns (bool) {\n return interfaceId == type(IERC7540Deposit).interfaceId || interfaceId == type(IERC7887Deposit).interfaceId\n || super.supportsInterface(interfaceId);\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-7540 claim\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC7575\n function maxDeposit(address controller) public view returns (uint256 maxAssets) {\n maxAssets = asyncManager().maxDeposit(this, controller);\n }\n\n /// @inheritdoc IERC7540Deposit\n function deposit(uint256 assets, address receiver, address controller) public returns (uint256 shares) {\n _validateController(controller);\n shares = asyncManager().deposit(this, assets, receiver, controller);\n emit Deposit(controller, receiver, assets, shares);\n }\n\n /// @inheritdoc IERC7575\n /// @notice When claiming deposit requests using deposit(), there can be some precision loss leading to dust.\n /// It is recommended to use mint() to claim deposit requests instead.\n function deposit(uint256 assets, address receiver) external returns (uint256 shares) {\n shares = deposit(assets, receiver, msg.sender);\n }\n\n /// @inheritdoc IERC7575\n function maxMint(address controller) public view returns (uint256 maxShares) {\n maxShares = asyncManager().maxMint(this, controller);\n }\n\n /// @inheritdoc IERC7540Deposit\n function mint(uint256 shares, address receiver, address controller) public returns (uint256 assets) {\n _validateController(controller);\n assets = asyncManager().mint(this, shares, receiver, controller);\n emit Deposit(controller, receiver, assets, shares);\n }\n\n /// @inheritdoc IERC7575\n function mint(uint256 shares, address receiver) public returns (uint256 assets) {\n assets = mint(shares, receiver, msg.sender);\n }\n\n /// @dev Strongly-typed accessor to the generic async redeem manager\n function asyncManager() public view returns (IAsyncRequestManager) {\n return IAsyncRequestManager(address(IAsyncRedeemVault(this).asyncRedeemManager()));\n }\n\n /// @dev Preview functions for ERC-7540 vaults revert\n function previewDeposit(uint256) external pure returns (uint256) {\n revert();\n }\n\n /// @dev Preview functions for ERC-7540 vaults revert\n function previewMint(uint256) external pure returns (uint256) {\n revert();\n }\n\n //----------------------------------------------------------------------------------------------\n // Event emitters\n //----------------------------------------------------------------------------------------------\n\n function onDepositClaimable(address controller, uint256 assets, uint256 shares) public virtual auth {\n emit DepositClaimable(controller, REQUEST_ID, assets, shares);\n }\n\n function onCancelDepositClaimable(address controller, uint256 assets) public virtual auth {\n emit CancelDepositClaimable(controller, REQUEST_ID, assets);\n }\n\n //----------------------------------------------------------------------------------------------\n // IBaseVault view\n //----------------------------------------------------------------------------------------------\n\n function vaultKind() public pure returns (VaultKind vaultKind_) {\n return VaultKind.Async;\n }\n}\n" + }, + "src/vaults/BalanceSheet.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {IAuth} from \"src/misc/interfaces/IAuth.sol\";\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {D18, d18} from \"src/misc/types/D18.sol\";\nimport {IERC6909} from \"src/misc/interfaces/IERC6909.sol\";\nimport {Recoverable} from \"src/misc/Recoverable.sol\";\nimport {SafeTransferLib} from \"src/misc/libraries/SafeTransferLib.sol\";\nimport {TransientStorageLib} from \"src/misc/libraries/TransientStorageLib.sol\";\n\nimport {IRoot} from \"src/common/interfaces/IRoot.sol\";\nimport {IGateway} from \"src/common/interfaces/IGateway.sol\";\nimport {MessageLib, UpdateContractType} from \"src/common/libraries/MessageLib.sol\";\nimport {IVaultMessageSender} from \"../common/interfaces/IGatewaySenders.sol\";\nimport {IBalanceSheetGatewayHandler} from \"src/common/interfaces/IGatewayHandlers.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\n\nimport {IPoolManager} from \"src/vaults/interfaces/IPoolManager.sol\";\nimport {IBalanceSheet, QueueAmount} from \"src/vaults/interfaces/IBalanceSheet.sol\";\nimport {IPoolEscrow} from \"src/vaults/interfaces/IEscrow.sol\";\nimport {IUpdateContract} from \"src/vaults/interfaces/IUpdateContract.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\nimport {IPoolEscrowProvider} from \"src/vaults/interfaces/factories/IPoolEscrowFactory.sol\";\n\n/// @title Balance Sheet\n/// @notice Management contract that integrates all balance sheet functions of a pool:\n/// - Issuing and revoking shares\n/// - Depositing and withdrawing assets\n/// - Force transferring shares\n///\n/// Share and asset updates to the Hub are optionally queued, to reduce the cost\n/// per transaction. Dequeuing can be triggered locally by the manager or from the Hub.\ncontract BalanceSheet is Auth, Recoverable, IBalanceSheet, IBalanceSheetGatewayHandler, IUpdateContract {\n using MathLib for *;\n using CastLib for bytes32;\n\n IRoot public immutable root;\n\n IPoolManager public poolManager;\n IVaultMessageSender public sender;\n IPoolEscrowProvider public poolEscrowProvider;\n\n mapping(PoolId => mapping(address => bool)) public manager;\n mapping(PoolId poolId => mapping(ShareClassId scId => bool)) public queueEnabled;\n mapping(PoolId poolId => mapping(ShareClassId scId => QueueAmount)) public queuedShares;\n mapping(PoolId poolId => mapping(ShareClassId scId => mapping(AssetId assetId => QueueAmount))) public queuedAssets;\n\n constructor(IRoot root_, address deployer) Auth(deployer) {\n root = root_;\n }\n\n /// @dev Check if the msg.sender is ward or a manager\n modifier authOrManager(PoolId poolId) {\n require(wards[msg.sender] == 1 || manager[poolId][msg.sender], IAuth.NotAuthorized());\n _;\n }\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n function file(bytes32 what, address data) external auth {\n if (what == \"poolManager\") poolManager = IPoolManager(data);\n else if (what == \"sender\") sender = IVaultMessageSender(data);\n else if (what == \"poolEscrowProvider\") poolEscrowProvider = IPoolEscrowProvider(data);\n else revert FileUnrecognizedParam();\n emit File(what, data);\n }\n\n function update(PoolId poolId, ShareClassId, /* scId */ bytes calldata payload) external auth {\n uint8 kind = uint8(MessageLib.updateContractType(payload));\n\n if (kind == uint8(UpdateContractType.UpdateManager)) {\n MessageLib.UpdateContractUpdateManager memory m = MessageLib.deserializeUpdateContractUpdateManager(payload);\n address who = m.who.toAddress();\n\n manager[poolId][who] = m.canManage;\n emit UpdateManager(poolId, who, m.canManage);\n } else {\n revert UnknownUpdateContractType();\n }\n }\n\n //----------------------------------------------------------------------------------------------\n // Management functions\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IBalanceSheet\n function deposit(PoolId poolId, ShareClassId scId, address asset, uint256 tokenId, address owner, uint128 amount)\n external\n authOrManager(poolId)\n {\n AssetId assetId = poolManager.assetToId(asset, tokenId);\n _noteDeposit(poolId, scId, assetId, asset, tokenId, owner, amount);\n _executeDeposit(poolId, asset, tokenId, owner, amount);\n }\n\n /// @inheritdoc IBalanceSheet\n /// @dev This function is mostly useful to keep higher level integrations CEI adherent.\n function noteDeposit(\n PoolId poolId,\n ShareClassId scId,\n address asset,\n uint256 tokenId,\n address owner,\n uint128 amount\n ) external authOrManager(poolId) {\n AssetId assetId = poolManager.assetToId(asset, tokenId);\n _noteDeposit(poolId, scId, assetId, asset, tokenId, owner, amount);\n }\n\n /// @inheritdoc IBalanceSheet\n function withdraw(\n PoolId poolId,\n ShareClassId scId,\n address asset,\n uint256 tokenId,\n address receiver,\n uint128 amount\n ) external authOrManager(poolId) {\n AssetId assetId = poolManager.assetToId(asset, tokenId);\n _withdraw(poolId, scId, assetId, asset, tokenId, receiver, amount);\n }\n\n /// @inheritdoc IBalanceSheet\n function issue(PoolId poolId, ShareClassId scId, address to, uint128 shares) external authOrManager(poolId) {\n _issue(poolId, scId, to, shares);\n }\n\n /// @inheritdoc IBalanceSheet\n function revoke(PoolId poolId, ShareClassId scId, address from, uint128 shares) external authOrManager(poolId) {\n _noteRevoke(poolId, scId, from, shares);\n _executeRevoke(poolId, scId, from, shares);\n }\n\n /// @inheritdoc IBalanceSheet\n /// @dev This function is mostly useful to keep higher level integrations CEI adherent.\n function noteRevoke(PoolId poolId, ShareClassId scId, address from, uint128 shares)\n external\n authOrManager(poolId)\n {\n _noteRevoke(poolId, scId, from, shares);\n }\n\n /// @inheritdoc IBalanceSheet\n function transferSharesFrom(PoolId poolId, ShareClassId scId, address from, address to, uint256 amount)\n external\n authOrManager(poolId)\n {\n require(!root.endorsed(from), CannotTransferFromEndorsedContract());\n IShareToken token = IShareToken(poolManager.shareToken(poolId, scId));\n token.authTransferFrom(from, from, to, amount);\n }\n\n /// @inheritdoc IBalanceSheet\n function overridePricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId, D18 value)\n external\n authOrManager(poolId)\n {\n TransientStorageLib.tstore(keccak256(abi.encode(\"pricePoolPerAsset\", poolId, scId, assetId)), value.raw());\n TransientStorageLib.tstore(keccak256(abi.encode(\"pricePoolPerAssetIsSet\", poolId, scId, assetId)), true);\n }\n\n /// @inheritdoc IBalanceSheet\n function overridePricePoolPerShare(PoolId poolId, ShareClassId scId, D18 value) external authOrManager(poolId) {\n TransientStorageLib.tstore(keccak256(abi.encode(\"pricePoolPerShare\", poolId, scId)), value.raw());\n TransientStorageLib.tstore(keccak256(abi.encode(\"pricePoolPerShareIsSet\", poolId, scId)), true);\n }\n\n //----------------------------------------------------------------------------------------------\n // Gateway handlers\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IBalanceSheetGatewayHandler\n function triggerDeposit(PoolId poolId, ShareClassId scId, AssetId assetId, address owner, uint128 amount)\n external\n auth\n {\n (address asset, uint256 tokenId) = poolManager.idToAsset(assetId);\n _noteDeposit(poolId, scId, assetId, asset, tokenId, owner, amount);\n _executeDeposit(poolId, asset, tokenId, owner, amount);\n }\n\n /// @inheritdoc IBalanceSheetGatewayHandler\n function triggerWithdraw(PoolId poolId, ShareClassId scId, AssetId assetId, address receiver, uint128 amount)\n external\n auth\n {\n (address asset, uint256 tokenId) = poolManager.idToAsset(assetId);\n _withdraw(poolId, scId, assetId, asset, tokenId, receiver, amount);\n }\n\n /// @inheritdoc IBalanceSheetGatewayHandler\n function triggerIssueShares(PoolId poolId, ShareClassId scId, address receiver, uint128 shares) external auth {\n _issue(poolId, scId, receiver, shares);\n }\n\n /// @inheritdoc IBalanceSheetGatewayHandler\n function setQueue(PoolId poolId, ShareClassId scId, bool enabled) external auth {\n queueEnabled[poolId][scId] = enabled;\n }\n\n /// @inheritdoc IBalanceSheetGatewayHandler\n function submitQueuedAssets(PoolId poolId, ShareClassId scId, AssetId assetId) external authOrManager(poolId) {\n _submitQueuedAssets(poolId, scId, assetId);\n }\n\n /// @inheritdoc IBalanceSheetGatewayHandler\n function submitQueuedShares(PoolId poolId, ShareClassId scId) external authOrManager(poolId) {\n _submitQueuedShares(poolId, scId);\n }\n\n //----------------------------------------------------------------------------------------------\n // Internal\n //----------------------------------------------------------------------------------------------\n\n function _noteDeposit(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n address asset,\n uint256 tokenId,\n address owner,\n uint128 amount\n ) internal {\n IPoolEscrow escrow = poolEscrowProvider.escrow(poolId);\n escrow.deposit(scId, asset, tokenId, amount);\n\n D18 pricePoolPerAsset_ = _pricePoolPerAsset(poolId, scId, assetId);\n emit Deposit(poolId, scId, asset, tokenId, owner, amount, pricePoolPerAsset_);\n\n if (queueEnabled[poolId][scId]) {\n queuedAssets[poolId][scId][assetId].increase += amount;\n } else {\n sender.sendUpdateHoldingAmount(poolId, scId, assetId, owner, amount, pricePoolPerAsset_, true);\n }\n }\n\n function _executeDeposit(PoolId poolId, address asset, uint256 tokenId, address owner, uint128 amount) internal {\n IPoolEscrow escrow = poolEscrowProvider.escrow(poolId);\n if (tokenId == 0) {\n SafeTransferLib.safeTransferFrom(asset, owner, address(escrow), amount);\n } else {\n IERC6909(asset).transferFrom(owner, address(escrow), tokenId, amount);\n }\n }\n\n function _withdraw(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n address asset,\n uint256 tokenId,\n address receiver,\n uint128 amount\n ) internal {\n IPoolEscrow escrow = poolEscrowProvider.escrow(poolId);\n escrow.withdraw(scId, asset, tokenId, amount);\n\n D18 pricePoolPerAsset_ = _pricePoolPerAsset(poolId, scId, assetId);\n emit Withdraw(poolId, scId, asset, tokenId, receiver, amount, pricePoolPerAsset_);\n\n if (queueEnabled[poolId][scId]) {\n queuedAssets[poolId][scId][assetId].decrease += amount;\n } else {\n sender.sendUpdateHoldingAmount(poolId, scId, assetId, receiver, amount, pricePoolPerAsset_, false);\n }\n\n escrow.authTransferTo(asset, tokenId, receiver, amount);\n }\n\n function _issue(PoolId poolId, ShareClassId scId, address to, uint128 shares) internal {\n emit Issue(poolId, scId, to, _pricePoolPerShare(poolId, scId), shares);\n\n if (queueEnabled[poolId][scId]) {\n queuedShares[poolId][scId].increase += shares;\n } else {\n sender.sendUpdateShares(poolId, scId, shares, true);\n }\n\n IShareToken token = poolManager.shareToken(poolId, scId);\n token.mint(to, shares);\n }\n\n function _noteRevoke(PoolId poolId, ShareClassId scId, address from, uint128 shares) internal {\n emit Revoke(poolId, scId, from, _pricePoolPerShare(poolId, scId), shares);\n\n if (queueEnabled[poolId][scId]) {\n queuedShares[poolId][scId].decrease += shares;\n } else {\n sender.sendUpdateShares(poolId, scId, shares, false);\n }\n }\n\n function _executeRevoke(PoolId poolId, ShareClassId scId, address from, uint128 shares) internal {\n IShareToken token = poolManager.shareToken(poolId, scId);\n token.authTransferFrom(from, from, address(this), shares);\n token.burn(address(this), shares);\n }\n\n function _submitQueuedShares(PoolId poolId, ShareClassId scId) internal {\n QueueAmount storage queue = queuedShares[poolId][scId];\n\n if (queue.increase > queue.decrease) {\n sender.sendUpdateShares(poolId, scId, queue.increase - queue.decrease, true);\n } else if (queue.decrease > queue.increase) {\n sender.sendUpdateShares(poolId, scId, queue.decrease - queue.increase, false);\n }\n\n queue.increase = 0;\n queue.decrease = 0;\n }\n\n function _submitQueuedAssets(PoolId poolId, ShareClassId scId, AssetId assetId) internal {\n QueueAmount storage queue = queuedAssets[poolId][scId][assetId];\n\n D18 pricePoolPerAsset = _pricePoolPerAsset(poolId, scId, assetId);\n if (queue.increase > queue.decrease) {\n sender.sendUpdateHoldingAmount(\n poolId, scId, assetId, address(0), queue.increase - queue.decrease, pricePoolPerAsset, true\n );\n } else if (queue.decrease > queue.increase) {\n sender.sendUpdateHoldingAmount(\n poolId, scId, assetId, address(0), queue.decrease - queue.increase, pricePoolPerAsset, false\n );\n }\n\n queue.increase = 0;\n queue.decrease = 0;\n }\n\n function _pricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId) internal view returns (D18) {\n if (TransientStorageLib.tloadBool(keccak256(abi.encode(\"pricePoolPerAssetIsSet\", poolId, scId, assetId)))) {\n return\n d18(TransientStorageLib.tloadUint128(keccak256(abi.encode(\"pricePoolPerAsset\", poolId, scId, assetId))));\n }\n\n D18 pricePoolPerAsset = poolManager.pricePoolPerAsset(poolId, scId, assetId, true);\n return pricePoolPerAsset;\n }\n\n function _pricePoolPerShare(PoolId poolId, ShareClassId scId) internal view returns (D18) {\n if (TransientStorageLib.tloadBool(keccak256(abi.encode(\"pricePoolPerShareIsSet\", poolId, scId)))) {\n return d18(TransientStorageLib.tloadUint128(keccak256(abi.encode(\"pricePoolPerShare\", poolId, scId))));\n }\n\n D18 pricePoolPerShare = poolManager.pricePoolPerShare(poolId, scId, true);\n return pricePoolPerShare;\n }\n}\n" + }, + "src/vaults/BaseRequestManager.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {D18} from \"src/misc/types/D18.sol\";\nimport {Recoverable} from \"src/misc/Recoverable.sol\";\nimport {IAuth} from \"src/misc/interfaces/IAuth.sol\";\n\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {PricingLib} from \"src/common/libraries/PricingLib.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nimport {IPoolManager, VaultDetails} from \"src/vaults/interfaces/IPoolManager.sol\";\nimport {IBaseRequestManager} from \"src/vaults/interfaces/investments/IBaseRequestManager.sol\";\nimport {IPoolEscrowProvider} from \"src/vaults/interfaces/factories/IPoolEscrowFactory.sol\";\nimport {IBaseVault, VaultKind} from \"src/vaults/interfaces/IBaseVaults.sol\";\nimport {IPoolEscrow, IEscrow} from \"src/vaults/interfaces/IEscrow.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\n\nabstract contract BaseRequestManager is Auth, Recoverable, IBaseRequestManager {\n using MathLib for uint256;\n\n address public immutable root;\n IEscrow public immutable globalEscrow;\n\n IPoolManager public poolManager;\n IPoolEscrowProvider public poolEscrowProvider;\n\n mapping(PoolId poolId => mapping(ShareClassId scId => mapping(AssetId assetId => IBaseVault vault))) public vault;\n\n constructor(IEscrow globalEscrow_, address root_, address deployer) Auth(deployer) {\n globalEscrow = globalEscrow_;\n root = root_;\n }\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IBaseRequestManager\n function file(bytes32 what, address data) external virtual auth {\n if (what == \"poolManager\") poolManager = IPoolManager(data);\n else if (what == \"poolEscrowProvider\") poolEscrowProvider = IPoolEscrowProvider(data);\n else revert FileUnrecognizedParam();\n emit File(what, data);\n }\n\n /// @inheritdoc IBaseRequestManager\n function addVault(PoolId poolId, ShareClassId scId, IBaseVault vault_, address asset_, AssetId assetId)\n public\n virtual\n auth\n {\n address token = vault_.share();\n\n require(vault_.asset() == asset_, AssetMismatch());\n require(address(vault[poolId][scId][assetId]) == address(0), VaultAlreadyExists());\n\n vault[poolId][scId][assetId] = IBaseVault(address(vault_));\n IAuth(token).rely(address(vault_));\n IShareToken(token).updateVault(vault_.asset(), address(vault_));\n rely(address(vault_));\n }\n\n /// @inheritdoc IBaseRequestManager\n function removeVault(PoolId poolId, ShareClassId scId, IBaseVault vault_, address asset_, AssetId assetId)\n public\n virtual\n auth\n {\n address token = vault_.share();\n\n require(vault_.asset() == asset_, AssetMismatch());\n require(address(vault[poolId][scId][assetId]) != address(0), VaultDoesNotExist());\n\n delete vault[poolId][scId][assetId];\n\n IAuth(token).deny(address(vault_));\n IShareToken(token).updateVault(vault_.asset(), address(0));\n deny(address(vault_));\n }\n\n //----------------------------------------------------------------------------------------------\n // View methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IBaseRequestManager\n function convertToShares(IBaseVault vault_, uint256 assets) public view virtual returns (uint256 shares) {\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n (D18 pricePoolPerAsset, D18 pricePoolPerShare) =\n poolManager.pricesPoolPer(vault_.poolId(), vault_.scId(), vaultDetails.assetId, false);\n\n return _assetToShareAmount(\n vault_, vaultDetails, assets, pricePoolPerAsset, pricePoolPerShare, MathLib.Rounding.Down\n );\n }\n\n /// @inheritdoc IBaseRequestManager\n function convertToAssets(IBaseVault vault_, uint256 shares) public view virtual returns (uint256 assets) {\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n (D18 pricePoolPerAsset, D18 pricePoolPerShare) =\n poolManager.pricesPoolPer(vault_.poolId(), vault_.scId(), vaultDetails.assetId, false);\n\n return _shareToAssetAmount(\n vault_, vaultDetails, shares, pricePoolPerAsset, pricePoolPerShare, MathLib.Rounding.Down\n );\n }\n\n /// @inheritdoc IBaseRequestManager\n function priceLastUpdated(IBaseVault vault_) public view virtual returns (uint64 lastUpdated) {\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n\n (uint64 shareLastUpdated,,) = poolManager.markersPricePoolPerShare(vault_.poolId(), vault_.scId());\n (uint64 assetLastUpdated,,) =\n poolManager.markersPricePoolPerAsset(vault_.poolId(), vault_.scId(), vaultDetails.assetId);\n\n // Choose the latest update to be the marker\n lastUpdated = MathLib.max(shareLastUpdated, assetLastUpdated).toUint64();\n }\n\n /// @inheritdoc IBaseRequestManager\n function poolEscrow(PoolId poolId) public view returns (IPoolEscrow) {\n return poolEscrowProvider.escrow(poolId);\n }\n\n /// @inheritdoc IBaseRequestManager\n function vaultByAssetId(PoolId poolId, ShareClassId scId, AssetId assetId) public view returns (IBaseVault) {\n return vault[poolId][scId][assetId];\n }\n\n function _assetToShareAmount(\n IBaseVault vault_,\n VaultDetails memory vaultDetails,\n uint256 assets,\n D18 pricePoolPerAsset,\n D18 pricePoolPerShare,\n MathLib.Rounding rounding\n ) internal view returns (uint256 shares) {\n return PricingLib.assetToShareAmount(\n vault_.share(),\n vaultDetails.asset,\n vaultDetails.tokenId,\n assets.toUint128(),\n pricePoolPerAsset,\n pricePoolPerShare,\n rounding\n );\n }\n\n function _shareToAssetAmount(\n IBaseVault vault_,\n VaultDetails memory vaultDetails,\n uint256 shares,\n D18 pricePoolPerAsset,\n D18 pricePoolPerShare,\n MathLib.Rounding rounding\n ) internal view returns (uint256 assets) {\n return PricingLib.shareToAssetAmount(\n vault_.share(),\n shares.toUint128(),\n vaultDetails.asset,\n vaultDetails.tokenId,\n pricePoolPerAsset,\n pricePoolPerShare,\n rounding\n );\n }\n}\n" + }, + "src/vaults/BaseVaults.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport \"src/misc/interfaces/IERC7540.sol\";\nimport \"src/misc/interfaces/IERC7575.sol\";\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {IERC20Metadata} from \"src/misc/interfaces/IERC20.sol\";\nimport {EIP712Lib} from \"src/misc/libraries/EIP712Lib.sol\";\nimport {SignatureLib} from \"src/misc/libraries/SignatureLib.sol\";\nimport {SafeTransferLib} from \"src/misc/libraries/SafeTransferLib.sol\";\nimport {Recoverable} from \"src/misc/Recoverable.sol\";\n\nimport {IRoot} from \"src/common/interfaces/IRoot.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nimport {IBaseVault, IAsyncRedeemVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\nimport {IERC7575} from \"src/misc/interfaces/IERC7575.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\nimport {IAsyncRedeemManager} from \"src/vaults/interfaces/investments/IAsyncRedeemManager.sol\";\nimport {ISyncDepositManager} from \"src/vaults/interfaces/investments/ISyncDepositManager.sol\";\nimport {IBaseRequestManager} from \"src/vaults/interfaces/investments/IBaseRequestManager.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\n\nabstract contract BaseVault is Auth, Recoverable, IBaseVault {\n /// @dev Requests for Centrifuge pool are non-fungible and all have ID = 0\n uint256 internal constant REQUEST_ID = 0;\n\n IRoot public immutable root;\n /// @dev this naming MUST NEVER change - due to legacy v2 vaults\n IBaseRequestManager public manager;\n\n /// @inheritdoc IBaseVault\n PoolId public immutable poolId;\n /// @inheritdoc IBaseVault\n ShareClassId public immutable scId;\n\n /// @inheritdoc IERC7575\n address public immutable asset;\n\n /// @inheritdoc IERC7575\n address public immutable share;\n uint8 internal immutable _shareDecimals;\n\n /// --- ERC7741 ---\n bytes32 private immutable nameHash;\n bytes32 private immutable versionHash;\n uint256 public immutable deploymentChainId;\n bytes32 private immutable _DOMAIN_SEPARATOR;\n bytes32 public constant AUTHORIZE_OPERATOR_TYPEHASH =\n keccak256(\"AuthorizeOperator(address controller,address operator,bool approved,bytes32 nonce,uint256 deadline)\");\n\n /// @inheritdoc IERC7741\n mapping(address controller => mapping(bytes32 nonce => bool used)) public authorizations;\n\n /// @inheritdoc IERC7540Operator\n mapping(address => mapping(address => bool)) public isOperator;\n\n constructor(\n PoolId poolId_,\n ShareClassId scId_,\n address asset_,\n IShareToken token_,\n address root_,\n IBaseRequestManager manager_\n ) Auth(msg.sender) {\n poolId = poolId_;\n scId = scId_;\n asset = asset_;\n share = address(token_);\n _shareDecimals = IERC20Metadata(share).decimals();\n root = IRoot(root_);\n manager = IBaseRequestManager(manager_);\n\n nameHash = keccak256(bytes(\"Centrifuge\"));\n versionHash = keccak256(bytes(\"1\"));\n deploymentChainId = block.chainid;\n _DOMAIN_SEPARATOR = EIP712Lib.calculateDomainSeparator(nameHash, versionHash);\n }\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n function file(bytes32 what, address data) external virtual auth {\n if (what == \"manager\") manager = IBaseRequestManager(data);\n else revert FileUnrecognizedParam();\n emit File(what, data);\n }\n\n /// @inheritdoc IERC7540Operator\n function setOperator(address operator, bool approved) public virtual returns (bool success) {\n require(msg.sender != operator, CannotSetSelfAsOperator());\n isOperator[msg.sender][operator] = approved;\n emit OperatorSet(msg.sender, operator, approved);\n success = true;\n }\n\n /// @inheritdoc IBaseVault\n function setEndorsedOperator(address owner, bool approved) public virtual {\n require(msg.sender != owner, CannotSetSelfAsOperator());\n require(root.endorsed(msg.sender), NotEndorsed());\n isOperator[owner][msg.sender] = approved;\n emit OperatorSet(owner, msg.sender, approved);\n }\n\n /// @inheritdoc IERC7741\n function DOMAIN_SEPARATOR() public view returns (bytes32) {\n return block.chainid == deploymentChainId\n ? _DOMAIN_SEPARATOR\n : EIP712Lib.calculateDomainSeparator(nameHash, versionHash);\n }\n\n /// @inheritdoc IERC7741\n function authorizeOperator(\n address controller,\n address operator,\n bool approved,\n bytes32 nonce,\n uint256 deadline,\n bytes memory signature\n ) external returns (bool success) {\n require(controller != operator, CannotSetSelfAsOperator());\n require(block.timestamp <= deadline, ExpiredAuthorization());\n require(!authorizations[controller][nonce], AlreadyUsedAuthorization());\n\n authorizations[controller][nonce] = true;\n\n bytes32 digest = keccak256(\n abi.encodePacked(\n \"\\x19\\x01\",\n DOMAIN_SEPARATOR(),\n keccak256(abi.encode(AUTHORIZE_OPERATOR_TYPEHASH, controller, operator, approved, nonce, deadline))\n )\n );\n\n require(SignatureLib.isValidSignature(controller, digest, signature), InvalidAuthorization());\n\n isOperator[controller][operator] = approved;\n emit OperatorSet(controller, operator, approved);\n\n success = true;\n }\n\n /// @inheritdoc IERC7741\n function invalidateNonce(bytes32 nonce) external {\n authorizations[msg.sender][nonce] = true;\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-165\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC165\n function supportsInterface(bytes4 interfaceId) public pure virtual override returns (bool) {\n return interfaceId == type(IERC7540Operator).interfaceId || interfaceId == type(IERC7741).interfaceId\n || interfaceId == type(IERC7714).interfaceId || interfaceId == type(IERC7575).interfaceId\n || interfaceId == type(IERC165).interfaceId;\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-4626\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC7575\n function totalAssets() external view returns (uint256) {\n return convertToAssets(IERC20Metadata(share).totalSupply());\n }\n\n /// @inheritdoc IERC7575\n /// @notice The calculation is based on the token price from the most recent epoch retrieved from Centrifuge.\n /// The actual conversion MAY change between order submission and execution.\n function convertToShares(uint256 assets) public view returns (uint256 shares) {\n shares = manager.convertToShares(this, assets);\n }\n\n /// @inheritdoc IERC7575\n /// @notice The calculation is based on the token price from the most recent epoch retrieved from Centrifuge.\n /// The actual conversion MAY change between order submission and execution.\n function convertToAssets(uint256 shares) public view returns (uint256 assets) {\n assets = manager.convertToAssets(this, shares);\n }\n\n //----------------------------------------------------------------------------------------------\n // Helpers\n //----------------------------------------------------------------------------------------------\n\n /// @notice Price of 1 unit of share, quoted in the decimals of the asset.\n function pricePerShare() external view returns (uint256) {\n return convertToAssets(10 ** _shareDecimals);\n }\n\n /// @notice Returns timestamp of the last share price update.\n function priceLastUpdated() external view returns (uint64) {\n return manager.priceLastUpdated(this);\n }\n\n /// @inheritdoc IERC7714\n function isPermissioned(address controller) external view returns (bool) {\n return IShareToken(share).checkTransferRestriction(address(0), controller, 0);\n }\n\n /// @notice Ensures msg.sender can operate on behalf of controller.\n function _validateController(address controller) internal view {\n require(controller == msg.sender || isOperator[controller][msg.sender], InvalidController());\n }\n}\n\nabstract contract BaseAsyncRedeemVault is BaseVault, IAsyncRedeemVault {\n IAsyncRedeemManager public asyncRedeemManager;\n\n constructor(IAsyncRedeemManager asyncRequestManager_) {\n asyncRedeemManager = asyncRequestManager_;\n }\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n function file(bytes32 what, address data) external virtual override auth {\n if (what == \"manager\") manager = IBaseRequestManager(data);\n else if (what == \"asyncRedeemManager\") asyncRedeemManager = IAsyncRedeemManager(data);\n else revert FileUnrecognizedParam();\n emit File(what, data);\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-7540 redeem\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC7540Redeem\n function requestRedeem(uint256 shares, address controller, address owner) public returns (uint256) {\n require(IShareToken(share).balanceOf(owner) >= shares, InsufficientBalance());\n\n // If msg.sender is operator of owner, the transfer is executed as if\n // the sender is the owner, to bypass the allowance check\n address sender = isOperator[owner][msg.sender] ? owner : msg.sender;\n\n require(asyncRedeemManager.requestRedeem(this, shares, controller, owner, sender), RequestRedeemFailed());\n IShareToken(share).authTransferFrom(sender, owner, address(manager.globalEscrow()), shares);\n\n emit RedeemRequest(controller, owner, REQUEST_ID, msg.sender, shares);\n return REQUEST_ID;\n }\n\n /// @inheritdoc IERC7540Redeem\n function pendingRedeemRequest(uint256, address controller) public view returns (uint256 pendingShares) {\n pendingShares = asyncRedeemManager.pendingRedeemRequest(this, controller);\n }\n\n /// @inheritdoc IERC7540Redeem\n function claimableRedeemRequest(uint256, address controller) external view returns (uint256 claimableShares) {\n claimableShares = maxRedeem(controller);\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-7887\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC7887Redeem\n function cancelRedeemRequest(uint256, address controller) external {\n _validateController(controller);\n asyncRedeemManager.cancelRedeemRequest(this, controller, msg.sender);\n emit CancelRedeemRequest(controller, REQUEST_ID, msg.sender);\n }\n\n /// @inheritdoc IERC7887Redeem\n function pendingCancelRedeemRequest(uint256, address controller) public view returns (bool isPending) {\n isPending = asyncRedeemManager.pendingCancelRedeemRequest(this, controller);\n }\n\n /// @inheritdoc IERC7887Redeem\n function claimableCancelRedeemRequest(uint256, address controller) public view returns (uint256 claimableShares) {\n claimableShares = asyncRedeemManager.claimableCancelRedeemRequest(this, controller);\n }\n\n /// @inheritdoc IERC7887Redeem\n function claimCancelRedeemRequest(uint256, address receiver, address controller)\n external\n returns (uint256 shares)\n {\n _validateController(controller);\n shares = asyncRedeemManager.claimCancelRedeemRequest(this, receiver, controller);\n emit CancelRedeemClaim(receiver, controller, REQUEST_ID, msg.sender, shares);\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-7540 claim\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC7575\n /// @notice DOES NOT support controller != msg.sender since shares are already transferred on requestRedeem\n function withdraw(uint256 assets, address receiver, address controller) public returns (uint256 shares) {\n _validateController(controller);\n shares = asyncRedeemManager.withdraw(this, assets, receiver, controller);\n emit Withdraw(msg.sender, receiver, controller, assets, shares);\n }\n\n /// @inheritdoc IERC7575\n /// @notice DOES NOT support controller != msg.sender since shares are already transferred on requestRedeem.\n /// When claiming redemption requests using redeem(), there can be some precision loss leading to dust.\n /// It is recommended to use withdraw() to claim redemption requests instead.\n function redeem(uint256 shares, address receiver, address controller) external returns (uint256 assets) {\n _validateController(controller);\n assets = asyncRedeemManager.redeem(this, shares, receiver, controller);\n emit Withdraw(msg.sender, receiver, controller, assets, shares);\n }\n\n //----------------------------------------------------------------------------------------------\n // Event emitters\n //----------------------------------------------------------------------------------------------\n\n function onRedeemRequest(address controller, address owner, uint256 shares) public virtual auth {\n emit RedeemRequest(controller, owner, REQUEST_ID, msg.sender, shares);\n }\n\n function onRedeemClaimable(address controller, uint256 assets, uint256 shares) public virtual auth {\n emit RedeemClaimable(controller, REQUEST_ID, assets, shares);\n }\n\n function onCancelRedeemClaimable(address controller, uint256 shares) public virtual auth {\n emit CancelRedeemClaimable(controller, REQUEST_ID, shares);\n }\n\n //----------------------------------------------------------------------------------------------\n // View methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC165\n function supportsInterface(bytes4 interfaceId) public pure virtual override(BaseVault, IERC165) returns (bool) {\n return super.supportsInterface(interfaceId) || interfaceId == type(IERC7540Redeem).interfaceId\n || interfaceId == type(IERC7887Redeem).interfaceId;\n }\n\n /// @inheritdoc IERC7575\n function maxWithdraw(address controller) public view returns (uint256 maxAssets) {\n maxAssets = asyncRedeemManager.maxWithdraw(this, controller);\n }\n\n /// @inheritdoc IERC7575\n function maxRedeem(address controller) public view returns (uint256 maxShares) {\n maxShares = asyncRedeemManager.maxRedeem(this, controller);\n }\n\n /// @dev Preview functions for ERC-7540 vaults revert\n function previewWithdraw(uint256) external pure returns (uint256) {\n revert();\n }\n\n /// @dev Preview functions for ERC-7540 vaults revert\n function previewRedeem(uint256) external pure returns (uint256) {\n revert();\n }\n}\n\nabstract contract BaseSyncDepositVault is BaseVault {\n ISyncDepositManager public syncDepositManager;\n\n constructor(ISyncDepositManager syncRequestManager_) {\n syncDepositManager = syncRequestManager_;\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-4626\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC7575\n function maxDeposit(address owner) public view returns (uint256 maxAssets) {\n maxAssets = syncDepositManager.maxDeposit(this, owner);\n }\n\n /// @inheritdoc IERC7575\n function previewDeposit(uint256 assets) external view override returns (uint256 shares) {\n shares = syncDepositManager.previewDeposit(this, msg.sender, assets);\n }\n\n /// @inheritdoc IERC7575\n function deposit(uint256 assets, address receiver) external returns (uint256 shares) {\n shares = syncDepositManager.deposit(this, assets, receiver, msg.sender);\n // NOTE: For security reasons, transfer must stay at end of call despite the fact that it logically should\n // happen before depositing in the manager\n SafeTransferLib.safeTransferFrom(asset, msg.sender, address(manager.poolEscrow(poolId)), assets);\n emit Deposit(receiver, msg.sender, assets, shares);\n }\n\n /// @inheritdoc IERC7575\n function maxMint(address owner) public view returns (uint256 maxShares) {\n maxShares = syncDepositManager.maxMint(this, owner);\n }\n\n /// @inheritdoc IERC7575\n function previewMint(uint256 shares) external view returns (uint256 assets) {\n assets = syncDepositManager.previewMint(this, msg.sender, shares);\n }\n\n /// @inheritdoc IERC7575\n function mint(uint256 shares, address receiver) public returns (uint256 assets) {\n assets = syncDepositManager.mint(this, shares, receiver, msg.sender);\n // NOTE: For security reasons, transfer must stay at end of call\n SafeTransferLib.safeTransferFrom(asset, msg.sender, address(manager.poolEscrow(poolId)), assets);\n emit Deposit(receiver, msg.sender, assets, shares);\n }\n\n /// @inheritdoc IERC165\n function supportsInterface(bytes4 interfaceId) public pure virtual override(BaseVault) returns (bool) {\n return super.supportsInterface(interfaceId);\n }\n}\n" + }, + "src/vaults/Escrow.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {IERC20} from \"src/misc/interfaces/IERC20.sol\";\nimport {IERC6909} from \"src/misc/interfaces/IERC6909.sol\";\nimport {SafeTransferLib} from \"src/misc/libraries/SafeTransferLib.sol\";\nimport {Recoverable} from \"src/misc/Recoverable.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {Holding, IPoolEscrow, IEscrow} from \"src/vaults/interfaces/IEscrow.sol\";\n\ncontract Escrow is Auth, IEscrow {\n constructor(address deployer) Auth(deployer) {}\n\n /// @inheritdoc IEscrow\n function authTransferTo(address asset, uint256 tokenId, address receiver, uint256 amount) public auth {\n if (tokenId == 0) {\n uint256 balance = IERC20(asset).balanceOf(address(this));\n require(balance >= amount, InsufficientBalance(asset, tokenId, amount, balance));\n\n SafeTransferLib.safeTransfer(asset, receiver, amount);\n } else {\n uint256 balance = IERC6909(asset).balanceOf(address(this), tokenId);\n require(balance >= amount, InsufficientBalance(asset, tokenId, amount, balance));\n\n IERC6909(asset).transfer(receiver, tokenId, amount);\n }\n\n emit AuthTransferTo(asset, tokenId, receiver, amount);\n }\n\n /// @inheritdoc IEscrow\n function authTransferTo(address asset, address receiver, uint256 amount) external auth {\n authTransferTo(asset, 0, receiver, amount);\n }\n}\n\n/// @title Escrow\n/// @notice Escrow contract that holds assets for a specific pool separated by share classes.\n/// Only wards can approve funds to be taken out.\ncontract PoolEscrow is Escrow, Recoverable, IPoolEscrow {\n /// @dev The underlying pool id\n PoolId public immutable poolId;\n\n mapping(ShareClassId scId => mapping(address asset => mapping(uint256 tokenId => Holding))) public holding;\n\n constructor(PoolId poolId_, address deployer) Escrow(deployer) {\n poolId = poolId_;\n }\n\n receive() external payable {}\n\n /// @inheritdoc IPoolEscrow\n function deposit(ShareClassId scId, address asset, uint256 tokenId, uint128 value) external auth {\n holding[scId][asset][tokenId].total += value;\n\n emit Deposit(asset, tokenId, poolId, scId, value);\n }\n\n /// @inheritdoc IPoolEscrow\n function withdraw(ShareClassId scId, address asset, uint256 tokenId, uint128 value) external auth {\n Holding storage holding_ = holding[scId][asset][tokenId];\n uint128 balance = holding_.total - holding_.reserved;\n require(balance >= value, InsufficientBalance(asset, tokenId, value, balance));\n\n holding_.total -= value;\n\n emit Withdraw(asset, tokenId, poolId, scId, value);\n }\n\n /// @inheritdoc IPoolEscrow\n function reserveIncrease(ShareClassId scId, address asset, uint256 tokenId, uint128 value) external auth {\n uint128 newValue = holding[scId][asset][tokenId].reserved + value;\n holding[scId][asset][tokenId].reserved = newValue;\n\n emit IncreaseReserve(asset, tokenId, poolId, scId, value, newValue);\n }\n\n /// @inheritdoc IPoolEscrow\n function reserveDecrease(ShareClassId scId, address asset, uint256 tokenId, uint128 value) external auth {\n uint128 prevValue = holding[scId][asset][tokenId].reserved;\n uint128 value_ = value;\n require(prevValue >= value_, InsufficientReservedAmount());\n\n uint128 newValue = prevValue - value_;\n holding[scId][asset][tokenId].reserved = newValue;\n\n emit DecreaseReserve(asset, tokenId, poolId, scId, value, newValue);\n }\n\n /// @inheritdoc IPoolEscrow\n function availableBalanceOf(ShareClassId scId, address asset, uint256 tokenId) public view returns (uint128) {\n Holding storage holding_ = holding[scId][asset][tokenId];\n if (holding_.total < holding_.reserved) return 0;\n return holding_.total - holding_.reserved;\n }\n}\n" + }, + "src/vaults/PoolManager.sol": { + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.28;\n\nimport {IERC20Metadata, IERC20Wrapper} from \"src/misc/interfaces/IERC20.sol\";\nimport {IERC6909MetadataExt} from \"src/misc/interfaces/IERC6909.sol\";\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {IAuth} from \"src/misc/interfaces/IAuth.sol\";\nimport {D18} from \"src/misc/types/D18.sol\";\nimport {Recoverable} from \"src/misc/Recoverable.sol\";\nimport {IERC165} from \"src/misc/interfaces/IERC7575.sol\";\nimport {ReentrancyProtection} from \"src/misc/ReentrancyProtection.sol\";\n\nimport {VaultUpdateKind, MessageLib, UpdateContractType} from \"src/common/libraries/MessageLib.sol\";\nimport {IGateway} from \"src/common/interfaces/IGateway.sol\";\nimport {IPoolManagerGatewayHandler} from \"src/common/interfaces/IGatewayHandlers.sol\";\nimport {IVaultMessageSender} from \"src/common/interfaces/IGatewaySenders.sol\";\nimport {newAssetId, AssetId} from \"src/common/types/AssetId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {PricingLib} from \"src/common/libraries/PricingLib.sol\";\n\nimport {IVaultFactory} from \"src/vaults/interfaces/factories/IVaultFactory.sol\";\nimport {IBaseVault, VaultKind} from \"src/vaults/interfaces/IBaseVaults.sol\";\nimport {IBaseRequestManager} from \"src/vaults/interfaces/investments/IBaseRequestManager.sol\";\nimport {ITokenFactory} from \"src/vaults/interfaces/factories/ITokenFactory.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\nimport {IPoolEscrowFactory} from \"src/vaults/interfaces/factories/IPoolEscrowFactory.sol\";\nimport {IHook} from \"src/common/interfaces/IHook.sol\";\nimport {IUpdateContract} from \"src/vaults/interfaces/IUpdateContract.sol\";\nimport {\n AssetIdKey,\n Pool,\n ShareClassDetails,\n Price,\n VaultDetails,\n IPoolManager\n} from \"src/vaults/interfaces/IPoolManager.sol\";\nimport {IAsyncRequestManager} from \"src/vaults/interfaces/investments/IAsyncRequestManager.sol\";\nimport {ISyncRequestManager} from \"src/vaults/interfaces/investments/ISyncRequestManager.sol\";\nimport {IPoolEscrow} from \"src/vaults/interfaces/IEscrow.sol\";\n\n/// @title Pool Manager\n/// @notice This contract manages which pools & share classes exist,\n/// as well as managing allowed pool currencies, and incoming and outgoing transfers.\ncontract PoolManager is\n Auth,\n Recoverable,\n ReentrancyProtection,\n IPoolManager,\n IUpdateContract,\n IPoolManagerGatewayHandler\n{\n using CastLib for *;\n using MessageLib for *;\n using BytesLib for bytes;\n using MathLib for uint256;\n\n uint8 internal constant MIN_DECIMALS = 2;\n uint8 internal constant MAX_DECIMALS = 18;\n\n IGateway public gateway;\n address public balanceSheet;\n ITokenFactory public tokenFactory;\n IVaultMessageSender public sender;\n IPoolEscrowFactory public poolEscrowFactory;\n IAsyncRequestManager public asyncRequestManager;\n ISyncRequestManager public syncRequestManager;\n\n uint64 internal _assetCounter;\n\n mapping(PoolId poolId => Pool) public pools;\n mapping(IVaultFactory factory => bool) public vaultFactory;\n\n mapping(IBaseVault => VaultDetails) internal _vaultDetails;\n mapping(AssetId assetId => AssetIdKey) internal _idToAsset;\n mapping(address asset => mapping(uint256 tokenId => AssetId assetId)) internal _assetToId;\n\n constructor(ITokenFactory tokenFactory_, address deployer) Auth(deployer) {\n tokenFactory = tokenFactory_;\n }\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IPoolManager\n function file(bytes32 what, address data) external auth {\n if (what == \"sender\") sender = IVaultMessageSender(data);\n else if (what == \"tokenFactory\") tokenFactory = ITokenFactory(data);\n else if (what == \"gateway\") gateway = IGateway(data);\n else if (what == \"balanceSheet\") balanceSheet = data;\n else if (what == \"poolEscrowFactory\") poolEscrowFactory = IPoolEscrowFactory(data);\n else if (what == \"asyncRequestManager\") asyncRequestManager = IAsyncRequestManager(data);\n else if (what == \"syncRequestManager\") syncRequestManager = ISyncRequestManager(data);\n else revert FileUnrecognizedParam();\n emit File(what, data);\n }\n\n /// @inheritdoc IPoolManager\n function file(bytes32 what, address factory, bool status) external auth {\n if (what == \"vaultFactory\") {\n vaultFactory[IVaultFactory(factory)] = status;\n } else {\n revert FileUnrecognizedParam();\n }\n emit File(what, factory, status);\n }\n\n //----------------------------------------------------------------------------------------------\n // Outgoing methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IPoolManager\n function transferShares(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bytes32 receiver, uint128 amount)\n external\n payable\n protected\n {\n IShareToken share = IShareToken(shareToken(poolId, scId));\n require(centrifugeId != sender.localCentrifugeId(), LocalTransferNotAllowed());\n require(\n share.checkTransferRestriction(msg.sender, address(uint160(centrifugeId)), amount),\n CrossChainTransferNotAllowed()\n );\n\n gateway.payTransaction{value: msg.value}(msg.sender);\n\n share.authTransferFrom(msg.sender, msg.sender, address(this), amount);\n share.burn(address(this), amount);\n\n emit TransferShares(centrifugeId, poolId, scId, msg.sender, receiver, amount);\n sender.sendTransferShares(centrifugeId, poolId, scId, receiver, amount);\n }\n\n // @inheritdoc IPoolManager\n function registerAsset(uint16 centrifugeId, address asset, uint256 tokenId)\n external\n payable\n protected\n returns (AssetId assetId)\n {\n string memory name;\n string memory symbol;\n uint8 decimals;\n\n decimals = _safeGetAssetDecimals(asset, tokenId);\n require(decimals >= MIN_DECIMALS, TooFewDecimals());\n require(decimals <= MAX_DECIMALS, TooManyDecimals());\n\n gateway.payTransaction{value: msg.value}(msg.sender);\n\n if (tokenId == 0) {\n IERC20Metadata meta = IERC20Metadata(asset);\n name = meta.name();\n symbol = meta.symbol();\n } else {\n IERC6909MetadataExt meta = IERC6909MetadataExt(asset);\n name = meta.name(tokenId);\n symbol = meta.symbol(tokenId);\n }\n\n assetId = _assetToId[asset][tokenId];\n if (assetId.raw() == 0) {\n _assetCounter++;\n assetId = newAssetId(sender.localCentrifugeId(), _assetCounter);\n\n _idToAsset[assetId] = AssetIdKey(asset, tokenId);\n _assetToId[asset][tokenId] = assetId;\n\n emit RegisterAsset(assetId, asset, tokenId, name, symbol, decimals);\n }\n\n sender.sendRegisterAsset(centrifugeId, assetId, decimals);\n }\n\n //----------------------------------------------------------------------------------------------\n // Incoming\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IPoolManagerGatewayHandler\n function addPool(PoolId poolId) public auth {\n Pool storage pool = pools[poolId];\n require(pool.createdAt == 0, PoolAlreadyAdded());\n pool.createdAt = block.timestamp;\n\n IPoolEscrow escrow = poolEscrowFactory.newEscrow(poolId);\n gateway.setRefundAddress(PoolId.wrap(poolId.raw()), escrow);\n\n emit AddPool(poolId);\n }\n\n /// @inheritdoc IPoolManagerGatewayHandler\n function addShareClass(\n PoolId poolId,\n ShareClassId scId,\n string memory name,\n string memory symbol,\n uint8 decimals,\n bytes32 salt,\n address hook\n ) public auth {\n require(decimals >= MIN_DECIMALS, TooFewDecimals());\n require(decimals <= MAX_DECIMALS, TooManyDecimals());\n require(isPoolActive(poolId), InvalidPool());\n\n Pool storage pool = pools[poolId];\n require(address(pool.shareClasses[scId].shareToken) == address(0), ShareClassAlreadyRegistered());\n\n // Hook can be address zero if the share token is fully permissionless and has no custom logic\n require(hook == address(0) || _isValidHook(hook), InvalidHook());\n\n address[] memory tokenWards = new address[](2);\n tokenWards[0] = address(this);\n // BalanceSheet needs this in order to mint shares\n tokenWards[1] = balanceSheet;\n\n IShareToken shareToken_ = tokenFactory.newToken(name, symbol, decimals, salt, tokenWards);\n\n if (hook != address(0)) {\n shareToken_.file(\"hook\", hook);\n }\n\n pool.shareClasses[scId].shareToken = shareToken_;\n\n emit AddShareClass(poolId, scId, shareToken_);\n }\n\n /// @inheritdoc IPoolManagerGatewayHandler\n function updateShareMetadata(PoolId poolId, ShareClassId scId, string memory name, string memory symbol)\n public\n auth\n {\n IShareToken shareToken_ = shareToken(poolId, scId);\n\n require(\n keccak256(bytes(shareToken_.name())) != keccak256(bytes(name))\n || keccak256(bytes(shareToken_.symbol())) != keccak256(bytes(symbol)),\n OldMetadata()\n );\n\n shareToken_.file(\"name\", name);\n shareToken_.file(\"symbol\", symbol);\n }\n\n /// @inheritdoc IPoolManagerGatewayHandler\n function updatePricePoolPerShare(PoolId poolId, ShareClassId scId, uint128 price, uint64 computedAt) public auth {\n ShareClassDetails storage shareClass = _shareClass(poolId, scId);\n\n require(computedAt >= shareClass.pricePoolPerShare.computedAt, CannotSetOlderPrice());\n\n shareClass.pricePoolPerShare = Price(price, computedAt, shareClass.pricePoolPerShare.maxAge);\n emit PriceUpdate(poolId, scId, price, computedAt);\n }\n\n /// @inheritdoc IPoolManagerGatewayHandler\n function updatePricePoolPerAsset(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n uint128 poolPerAsset_,\n uint64 computedAt\n ) public auth {\n ShareClassDetails storage shareClass = _shareClass(poolId, scId);\n\n (address asset, uint256 tokenId) = idToAsset(assetId);\n Price storage poolPerAsset = shareClass.pricePoolPerAsset[asset][tokenId];\n require(computedAt >= poolPerAsset.computedAt, CannotSetOlderPrice());\n\n // Disable expiration of the price\n if (poolPerAsset.computedAt == 0) {\n poolPerAsset.maxAge = type(uint64).max;\n }\n poolPerAsset.price = poolPerAsset_;\n poolPerAsset.computedAt = computedAt;\n\n emit PriceUpdate(poolId, scId, asset, tokenId, poolPerAsset_, computedAt);\n }\n\n /// @inheritdoc IPoolManagerGatewayHandler\n function updateRestriction(PoolId poolId, ShareClassId scId, bytes memory update_) public auth {\n IShareToken shareToken_ = shareToken(poolId, scId);\n address hook = shareToken_.hook();\n require(hook != address(0), InvalidHook());\n IHook(hook).updateRestriction(address(shareToken_), update_);\n }\n\n /// @inheritdoc IPoolManagerGatewayHandler\n function updateContract(PoolId poolId, ShareClassId scId, address target, bytes memory update_) public auth {\n if (target == address(this)) {\n update(poolId, scId, update_);\n } else {\n IUpdateContract(target).update(poolId, scId, update_);\n }\n\n emit UpdateContract(poolId, scId, target, update_);\n }\n\n /// @inheritdoc IPoolManagerGatewayHandler\n function updateShareHook(PoolId poolId, ShareClassId scId, address hook) public auth {\n IShareToken shareToken_ = shareToken(poolId, scId);\n require(hook != shareToken_.hook(), OldHook());\n shareToken_.file(\"hook\", hook);\n }\n\n /// @inheritdoc IPoolManagerGatewayHandler\n function handleTransferShares(PoolId poolId, ShareClassId scId, address destinationAddress, uint128 amount)\n public\n auth\n {\n IShareToken shareToken_ = shareToken(poolId, scId);\n\n shareToken_.mint(destinationAddress, amount);\n }\n\n /// @inheritdoc IUpdateContract\n /// @notice The pool manager either deploys the vault if a factory address is provided\n /// or it simply links/unlinks the vault.\n function update(PoolId poolId, ShareClassId scId, bytes memory payload) public auth {\n uint8 kind = uint8(MessageLib.updateContractType(payload));\n\n if (kind == uint8(UpdateContractType.VaultUpdate)) {\n MessageLib.UpdateContractVaultUpdate memory m = MessageLib.deserializeUpdateContractVaultUpdate(payload);\n\n if (m.kind == uint8(VaultUpdateKind.DeployAndLink)) {\n IVaultFactory factory = IVaultFactory(m.vaultOrFactory.toAddress());\n\n IBaseVault vault = deployVault(poolId, scId, AssetId.wrap(m.assetId), factory);\n linkVault(poolId, scId, AssetId.wrap(m.assetId), vault);\n } else {\n IBaseVault vault = IBaseVault(m.vaultOrFactory.toAddress());\n\n // Needed as safeguard against non-validated vaults\n // I.e. we only accept vaults that have been deployed by the pool manager\n require(_vaultDetails[vault].asset != address(0), UnknownVault());\n\n if (m.kind == uint8(VaultUpdateKind.Link)) {\n linkVault(poolId, scId, AssetId.wrap(m.assetId), vault);\n } else if (m.kind == uint8(VaultUpdateKind.Unlink)) {\n unlinkVault(poolId, scId, AssetId.wrap(m.assetId), vault);\n } else {\n revert MalformedVaultUpdateMessage();\n }\n }\n } else if (kind == uint8(UpdateContractType.MaxAssetPriceAge)) {\n MessageLib.UpdateContractMaxAssetPriceAge memory m =\n MessageLib.deserializeUpdateContractMaxAssetPriceAge(payload);\n\n ShareClassDetails storage shareClass = _shareClass(poolId, scId);\n require(m.assetId != 0, UnknownAsset());\n\n (address asset, uint256 tokenId) = idToAsset(AssetId.wrap(m.assetId));\n shareClass.pricePoolPerAsset[asset][tokenId].maxAge = m.maxPriceAge;\n emit UpdateMaxAssetPriceAge(poolId, scId, asset, tokenId, m.maxPriceAge);\n } else if (kind == uint8(UpdateContractType.MaxSharePriceAge)) {\n MessageLib.UpdateContractMaxSharePriceAge memory m =\n MessageLib.deserializeUpdateContractMaxSharePriceAge(payload);\n\n ShareClassDetails storage shareClass = _shareClass(poolId, scId);\n\n shareClass.pricePoolPerShare.maxAge = m.maxPriceAge;\n emit UpdateMaxSharePriceAge(poolId, scId, m.maxPriceAge);\n } else {\n revert UnknownUpdateContractType();\n }\n }\n\n /// @inheritdoc IPoolManager\n function linkVault(PoolId poolId, ShareClassId scId, AssetId assetId, IBaseVault vault) public auth {\n _shareClass(poolId, scId);\n\n AssetIdKey memory assetIdKey = _idToAsset[assetId];\n\n IBaseRequestManager manager = vault.manager();\n manager.addVault(poolId, scId, vault, assetIdKey.asset, assetId);\n\n _vaultDetails[vault].isLinked = true;\n\n emit LinkVault(poolId, scId, assetIdKey.asset, assetIdKey.tokenId, vault);\n }\n\n /// @inheritdoc IPoolManager\n function unlinkVault(PoolId poolId, ShareClassId scId, AssetId assetId, IBaseVault vault) public auth {\n _shareClass(poolId, scId);\n\n AssetIdKey memory assetIdKey = _idToAsset[assetId];\n\n IBaseRequestManager manager = vault.manager();\n manager.removeVault(poolId, scId, vault, assetIdKey.asset, assetId);\n\n _vaultDetails[vault].isLinked = false;\n\n emit UnlinkVault(poolId, scId, assetIdKey.asset, assetIdKey.tokenId, vault);\n }\n\n /// @inheritdoc IPoolManager\n function deployVault(PoolId poolId, ShareClassId scId, AssetId assetId, IVaultFactory factory)\n public\n auth\n returns (IBaseVault)\n {\n ShareClassDetails storage shareClass = _shareClass(poolId, scId);\n require(vaultFactory[factory], InvalidFactory());\n\n // Rely investment manager on vault so it can mint tokens\n address[] memory vaultWards = new address[](0);\n\n // Deploy vault\n AssetIdKey memory assetIdKey = _idToAsset[assetId];\n IBaseVault vault = IVaultFactory(factory).newVault(\n poolId, scId, assetIdKey.asset, assetIdKey.tokenId, shareClass.shareToken, vaultWards\n );\n\n // Check whether asset is an ERC20 token wrapper\n (bool success, bytes memory data) =\n assetIdKey.asset.staticcall(abi.encodeWithSelector(IERC20Wrapper.underlying.selector));\n // On success, the returned 20 byte address is padded to 32 bytes\n bool isWrappedERC20 = success && data.length == 32;\n _vaultDetails[vault] = VaultDetails(assetId, assetIdKey.asset, assetIdKey.tokenId, isWrappedERC20, false);\n\n // NOTE - Reverting the manager approvals is not easy. We SHOULD do that if we phase-out a manager\n VaultKind vaultKind = _relyShareToken(vault, shareClass.shareToken);\n\n emit DeployVault(poolId, scId, assetIdKey.asset, assetIdKey.tokenId, factory, vault, vaultKind);\n return vault;\n }\n\n //----------------------------------------------------------------------------------------------\n // View methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IPoolManager\n function isPoolActive(PoolId poolId) public view returns (bool) {\n return pools[poolId].createdAt > 0;\n }\n\n /// @inheritdoc IPoolManager\n function shareToken(PoolId poolId, ShareClassId scId) public view returns (IShareToken) {\n ShareClassDetails storage shareClass = pools[poolId].shareClasses[scId];\n require(address(shareClass.shareToken) != address(0), UnknownToken());\n return shareClass.shareToken;\n }\n\n /// @inheritdoc IPoolManager\n function vaultDetails(IBaseVault vault) public view returns (VaultDetails memory details) {\n details = _vaultDetails[vault];\n require(details.asset != address(0), UnknownVault());\n }\n\n /// @inheritdoc IPoolManager\n function isLinked(PoolId, /* poolId */ ShareClassId, /* scId */ address, /* asset */ IBaseVault vault)\n public\n view\n returns (bool)\n {\n return _vaultDetails[vault].isLinked;\n }\n\n /// @inheritdoc IPoolManager\n function idToAsset(AssetId assetId) public view returns (address asset, uint256 tokenId) {\n AssetIdKey memory assetIdKey = _idToAsset[assetId];\n require(assetIdKey.asset != address(0), UnknownAsset());\n return (assetIdKey.asset, assetIdKey.tokenId);\n }\n\n /// @inheritdoc IPoolManager\n function assetToId(address asset, uint256 tokenId) public view returns (AssetId assetId) {\n assetId = _assetToId[asset][tokenId];\n require(assetId.raw() != 0, UnknownAsset());\n }\n\n /// @inheritdoc IPoolManager\n function priceAssetPerShare(PoolId poolId, ShareClassId scId, AssetId assetId, bool checkValidity)\n public\n view\n returns (D18 price)\n {\n (Price memory poolPerAsset, Price memory poolPerShare) = _pricesPoolPer(poolId, scId, assetId, checkValidity);\n\n price = PricingLib.priceAssetPerShare(poolPerShare.asPrice(), poolPerAsset.asPrice());\n }\n\n /// @inheritdoc IPoolManager\n function pricePoolPerShare(PoolId poolId, ShareClassId scId, bool checkValidity) public view returns (D18 price) {\n ShareClassDetails storage shareClass = _shareClass(poolId, scId);\n\n if (checkValidity) {\n require(shareClass.pricePoolPerShare.isValid(), InvalidPrice());\n }\n\n price = shareClass.pricePoolPerShare.asPrice();\n }\n\n /// @inheritdoc IPoolManager\n function pricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId, bool checkValidity)\n public\n view\n returns (D18 price)\n {\n (Price memory poolPerAsset,) = _pricesPoolPer(poolId, scId, assetId, false);\n\n if (checkValidity) {\n require(poolPerAsset.isValid(), InvalidPrice());\n }\n\n price = poolPerAsset.asPrice();\n }\n\n /// @inheritdoc IPoolManager\n function pricesPoolPer(PoolId poolId, ShareClassId scId, AssetId assetId, bool checkValidity)\n public\n view\n returns (D18 pricePoolPerAsset_, D18 pricePoolPerShare_)\n {\n (Price memory poolPerAsset, Price memory poolPerShare) = _pricesPoolPer(poolId, scId, assetId, checkValidity);\n return (poolPerAsset.asPrice(), poolPerShare.asPrice());\n }\n\n /// @inheritdoc IPoolManager\n function markersPricePoolPerShare(PoolId poolId, ShareClassId scId)\n external\n view\n returns (uint64 computedAt, uint64 maxAge, uint64 validUntil)\n {\n ShareClassDetails storage shareClass = _shareClass(poolId, scId);\n computedAt = shareClass.pricePoolPerShare.computedAt;\n maxAge = shareClass.pricePoolPerShare.maxAge;\n validUntil = shareClass.pricePoolPerShare.validUntil();\n }\n\n /// @inheritdoc IPoolManager\n function markersPricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId)\n external\n view\n returns (uint64 computedAt, uint64 maxAge, uint64 validUntil)\n {\n (Price memory poolPerAsset,) = _pricesPoolPer(poolId, scId, assetId, false);\n computedAt = poolPerAsset.computedAt;\n maxAge = poolPerAsset.maxAge;\n validUntil = poolPerAsset.validUntil();\n }\n\n //----------------------------------------------------------------------------------------------\n // Internal methods\n //----------------------------------------------------------------------------------------------\n\n function _pricesPoolPer(PoolId poolId, ShareClassId scId, AssetId assetId, bool checkValidity)\n internal\n view\n returns (Price memory poolPerAsset, Price memory poolPerShare)\n {\n ShareClassDetails storage shareClass = _shareClass(poolId, scId);\n\n (address asset, uint256 tokenId) = idToAsset(assetId);\n poolPerAsset = shareClass.pricePoolPerAsset[asset][tokenId];\n poolPerShare = shareClass.pricePoolPerShare;\n\n if (checkValidity) {\n require(poolPerAsset.isValid(), InvalidPrice());\n require(poolPerShare.isValid(), InvalidPrice());\n }\n }\n\n /// @dev Sets up approval permissions for pool, i.e. the pool escrow, the base vault manager and potentially a\n /// secondary manager (in case of partially sync vault)\n function _relyShareToken(IBaseVault vault, IShareToken shareToken_) internal returns (VaultKind) {\n IBaseRequestManager manager = vault.manager();\n IAuth(address(shareToken_)).rely(address(manager));\n\n // For sync deposit & async redeem vault, also repeat above for async manager\n VaultKind vaultKind = vault.vaultKind();\n if (vaultKind == VaultKind.SyncDepositAsyncRedeem) {\n IAuth(address(shareToken_)).rely(address(asyncRequestManager));\n }\n\n return vaultKind;\n }\n\n function _safeGetAssetDecimals(address asset, uint256 tokenId) private view returns (uint8) {\n bytes memory callData;\n\n if (tokenId == 0) {\n callData = abi.encodeWithSignature(\"decimals()\");\n } else {\n callData = abi.encodeWithSignature(\"decimals(uint256)\", tokenId);\n }\n\n (bool success, bytes memory data) = asset.staticcall(callData);\n require(success && data.length >= 32, AssetMissingDecimals());\n\n return abi.decode(data, (uint8));\n }\n\n function _isValidHook(address hook) internal view returns (bool) {\n (bool success, bytes memory data) =\n hook.staticcall(abi.encodeWithSelector(IERC165.supportsInterface.selector, type(IHook).interfaceId));\n\n return success && data.length == 32 && abi.decode(data, (bool));\n }\n\n function _shareClass(PoolId poolId, ShareClassId scId)\n internal\n view\n returns (ShareClassDetails storage shareClass)\n {\n shareClass = pools[poolId].shareClasses[scId];\n require(address(shareClass.shareToken) != address(0), ShareTokenDoesNotExist());\n }\n}\n" + }, + "src/vaults/SyncDepositVault.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IERC165} from \"src/misc/interfaces/IERC7575.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nimport {BaseVault, BaseAsyncRedeemVault, BaseSyncDepositVault} from \"src/vaults/BaseVaults.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\nimport {IAsyncRedeemManager} from \"src/vaults/interfaces/investments/IAsyncRedeemManager.sol\";\nimport {ISyncDepositManager} from \"src/vaults/interfaces/investments/ISyncDepositManager.sol\";\nimport {IBaseRequestManager} from \"src/vaults/interfaces/investments/IBaseRequestManager.sol\";\nimport {VaultKind} from \"src/vaults/interfaces/IBaseVaults.sol\";\n\n/// @title SyncDepositVault\n/// @notice Partially (a)synchronous Tokenized Vault implementation with synchronous deposits\n/// and asynchronous redemptions following ERC-7540.\n///\n/// @dev Each vault issues shares of Centrifuge share class tokens as restricted ERC-20 tokens\n/// against asset deposits based on the current share price.\ncontract SyncDepositVault is BaseSyncDepositVault, BaseAsyncRedeemVault {\n constructor(\n PoolId poolId_,\n ShareClassId scId_,\n address asset_,\n IShareToken token_,\n address root_,\n ISyncDepositManager syncDepositManager_,\n IAsyncRedeemManager asyncRedeemManager_\n )\n BaseVault(poolId_, scId_, asset_, token_, root_, syncDepositManager_)\n BaseSyncDepositVault(syncDepositManager_)\n BaseAsyncRedeemVault(asyncRedeemManager_)\n {}\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n function file(bytes32 what, address data) external override(BaseAsyncRedeemVault, BaseVault) auth {\n if (what == \"manager\") manager = IBaseRequestManager(data);\n else if (what == \"asyncRedeemManager\") asyncRedeemManager = IAsyncRedeemManager(data);\n else if (what == \"syncDepositManager\") syncDepositManager = ISyncDepositManager(data);\n else revert FileUnrecognizedParam();\n emit File(what, data);\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-165\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC165\n function supportsInterface(bytes4 interfaceId)\n public\n pure\n override(BaseAsyncRedeemVault, BaseSyncDepositVault)\n returns (bool)\n {\n return super.supportsInterface(interfaceId);\n }\n\n //----------------------------------------------------------------------------------------------\n // IBaseVault view\n //----------------------------------------------------------------------------------------------\n\n function vaultKind() public pure returns (VaultKind vaultKind_) {\n return VaultKind.SyncDepositAsyncRedeem;\n }\n}\n" + }, + "src/vaults/SyncRequestManager.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IERC165} from \"forge-std/interfaces/IERC165.sol\";\nimport {IERC7540Redeem} from \"src/misc/interfaces/IERC7540.sol\";\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {IAuth} from \"src/misc/interfaces/IAuth.sol\";\nimport {d18, D18} from \"src/misc/types/D18.sol\";\n\nimport {MessageLib, UpdateContractType} from \"src/common/libraries/MessageLib.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {PricingLib} from \"src/common/libraries/PricingLib.sol\";\n\nimport {BaseRequestManager} from \"src/vaults/BaseRequestManager.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\nimport {IAsyncRedeemVault, IBaseVault, VaultKind} from \"src/vaults/interfaces/IBaseVaults.sol\";\nimport {IPoolManager, VaultDetails} from \"src/vaults/interfaces/IPoolManager.sol\";\nimport {IBalanceSheet} from \"src/vaults/interfaces/IBalanceSheet.sol\";\nimport {IBaseRequestManager} from \"src/vaults/interfaces/investments/IBaseRequestManager.sol\";\nimport {\n ISyncRequestManager,\n Prices,\n ISyncDepositValuation\n} from \"src/vaults/interfaces/investments/ISyncRequestManager.sol\";\nimport {IDepositManager} from \"src/vaults/interfaces/investments/IDepositManager.sol\";\nimport {ISyncDepositManager} from \"src/vaults/interfaces/investments/ISyncDepositManager.sol\";\nimport {IUpdateContract} from \"src/vaults/interfaces/IUpdateContract.sol\";\nimport {IEscrow} from \"src/vaults/interfaces/IEscrow.sol\";\nimport {IPoolEscrowProvider} from \"src/vaults/interfaces/factories/IPoolEscrowFactory.sol\";\nimport {IAsyncRedeemManager} from \"src/vaults/interfaces/investments/IAsyncRedeemManager.sol\";\n\n/// @title Sync Investment Manager\n/// @notice This is the main contract vaults interact with for\n/// both incoming and outgoing investment transactions.\ncontract SyncRequestManager is BaseRequestManager, ISyncRequestManager {\n using BytesLib for bytes;\n using MathLib for *;\n using CastLib for *;\n using MessageLib for *;\n\n IBalanceSheet public balanceSheet;\n\n mapping(PoolId => mapping(ShareClassId scId => ISyncDepositValuation)) public valuation;\n mapping(PoolId => mapping(ShareClassId scId => mapping(address asset => mapping(uint256 tokenId => uint128))))\n public maxReserve;\n\n constructor(IEscrow globalEscrow_, address root_, address deployer)\n BaseRequestManager(globalEscrow_, root_, deployer)\n {}\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IBaseRequestManager\n function file(bytes32 what, address data) external override(IBaseRequestManager, BaseRequestManager) auth {\n if (what == \"poolManager\") poolManager = IPoolManager(data);\n else if (what == \"balanceSheet\") balanceSheet = IBalanceSheet(data);\n else if (what == \"poolEscrowProvider\") poolEscrowProvider = IPoolEscrowProvider(data);\n else revert FileUnrecognizedParam();\n emit File(what, data);\n }\n\n /// @inheritdoc IUpdateContract\n function update(PoolId poolId, ShareClassId scId, bytes memory payload) external auth {\n uint8 kind = uint8(MessageLib.updateContractType(payload));\n\n if (kind == uint8(UpdateContractType.Valuation)) {\n MessageLib.UpdateContractValuation memory m = MessageLib.deserializeUpdateContractValuation(payload);\n\n require(address(poolManager.shareToken(poolId, scId)) != address(0), ShareTokenDoesNotExist());\n\n setValuation(poolId, scId, m.valuation.toAddress());\n } else if (kind == uint8(UpdateContractType.SyncDepositMaxReserve)) {\n MessageLib.UpdateContractSyncDepositMaxReserve memory m =\n MessageLib.deserializeUpdateContractSyncDepositMaxReserve(payload);\n\n require(address(poolManager.shareToken(poolId, scId)) != address(0), ShareTokenDoesNotExist());\n (address asset, uint256 tokenId) = poolManager.idToAsset(AssetId.wrap(m.assetId));\n\n setMaxReserve(poolId, scId, asset, tokenId, m.maxReserve);\n } else {\n revert UnknownUpdateContractType();\n }\n }\n\n /// @inheritdoc IBaseRequestManager\n function addVault(PoolId poolId, ShareClassId scId, IBaseVault vault_, address asset_, AssetId assetId)\n public\n override(BaseRequestManager, IBaseRequestManager)\n auth\n {\n super.addVault(poolId, scId, vault_, asset_, assetId);\n\n (, uint256 tokenId) = poolManager.idToAsset(assetId);\n setMaxReserve(poolId, scId, asset_, tokenId, type(uint128).max);\n\n VaultKind vaultKind_ = vault_.vaultKind();\n if (vaultKind_ == VaultKind.SyncDepositAsyncRedeem) {\n IAsyncRedeemManager asyncRequestManager = IAsyncRedeemVault(address(vault_)).asyncRedeemManager();\n require(address(asyncRequestManager) != address(0), SecondaryManagerDoesNotExist());\n asyncRequestManager.addVault(poolId, scId, vault_, asset_, assetId);\n }\n }\n\n /// @inheritdoc IBaseRequestManager\n function removeVault(PoolId poolId, ShareClassId scId, IBaseVault vault_, address asset_, AssetId assetId)\n public\n override(BaseRequestManager, IBaseRequestManager)\n auth\n {\n super.removeVault(poolId, scId, vault_, asset_, assetId);\n\n (, uint256 tokenId) = poolManager.idToAsset(assetId);\n delete maxReserve[poolId][scId][asset_][tokenId];\n\n VaultKind vaultKind_ = vault_.vaultKind();\n if (vaultKind_ == VaultKind.SyncDepositAsyncRedeem) {\n IAsyncRedeemManager asyncRequestManager = IAsyncRedeemVault(address(vault_)).asyncRedeemManager();\n require(address(asyncRequestManager) != address(0), SecondaryManagerDoesNotExist());\n asyncRequestManager.removeVault(poolId, scId, vault_, asset_, assetId);\n }\n }\n\n /// @inheritdoc ISyncRequestManager\n function setValuation(PoolId poolId, ShareClassId scId, address valuation_) public auth {\n valuation[poolId][scId] = ISyncDepositValuation(valuation_);\n\n emit SetValuation(poolId, scId, address(valuation_));\n }\n\n /// @inheritdoc ISyncRequestManager\n function setMaxReserve(PoolId poolId, ShareClassId scId, address asset, uint256 tokenId, uint128 maxReserve_)\n public\n auth\n {\n maxReserve[poolId][scId][asset][tokenId] = maxReserve_;\n\n emit SetMaxReserve(poolId, scId, asset, tokenId, maxReserve_);\n }\n\n //----------------------------------------------------------------------------------------------\n // Deposit handlers\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IDepositManager\n function mint(IBaseVault vault_, uint256 shares, address receiver, address owner)\n external\n auth\n returns (uint256 assets)\n {\n require(maxMint(vault_, owner) >= shares, ExceedsMaxMint());\n assets = previewMint(vault_, owner, shares);\n\n _issueShares(vault_, shares.toUint128(), receiver, owner, assets.toUint128());\n }\n\n /// @inheritdoc IDepositManager\n function deposit(IBaseVault vault_, uint256 assets, address receiver, address owner)\n external\n auth\n returns (uint256 shares)\n {\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n require(poolManager.isLinked(vault_.poolId(), vault_.scId(), vaultDetails.asset, vault_), AssetNotAllowed());\n\n require(maxDeposit(vault_, owner) >= assets, ExceedsMaxDeposit());\n shares = previewDeposit(vault_, owner, assets);\n\n _issueShares(vault_, shares.toUint128(), receiver, owner, assets.toUint128());\n }\n\n //----------------------------------------------------------------------------------------------\n // View methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc ISyncDepositManager\n function previewMint(IBaseVault vault_, address, /* sender */ uint256 shares)\n public\n view\n returns (uint256 assets)\n {\n return _shareToAssetAmount(vault_, shares, MathLib.Rounding.Up);\n }\n\n /// @inheritdoc ISyncDepositManager\n function previewDeposit(IBaseVault vault_, address, /* sender */ uint256 assets)\n public\n view\n returns (uint256 shares)\n {\n return convertToShares(vault_, assets);\n }\n\n /// @inheritdoc IDepositManager\n function maxMint(IBaseVault vault_, address /* owner */ ) public view returns (uint256) {\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n uint128 maxAssets = _maxDeposit(vault_.poolId(), vault_.scId(), vaultDetails.asset, vaultDetails.tokenId);\n return convertToShares(vault_, maxAssets);\n }\n\n /// @inheritdoc IDepositManager\n function maxDeposit(IBaseVault vault_, address /* owner */ ) public view returns (uint256) {\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n return _maxDeposit(vault_.poolId(), vault_.scId(), vaultDetails.asset, vaultDetails.tokenId);\n }\n\n /// @inheritdoc IBaseRequestManager\n function convertToShares(IBaseVault vault_, uint256 assets)\n public\n view\n override(IBaseRequestManager, BaseRequestManager)\n returns (uint256 shares)\n {\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n Prices memory prices_ = prices(vault_.poolId(), vault_.scId(), vaultDetails.assetId);\n\n return super._assetToShareAmount(\n vault_, vaultDetails, assets, prices_.poolPerAsset, prices_.poolPerShare, MathLib.Rounding.Down\n );\n }\n\n /// @inheritdoc IBaseRequestManager\n function convertToAssets(IBaseVault vault_, uint256 shares)\n public\n view\n override(IBaseRequestManager, BaseRequestManager)\n returns (uint256 assets)\n {\n return _shareToAssetAmount(vault_, shares, MathLib.Rounding.Down);\n }\n\n /// @inheritdoc ISyncDepositValuation\n function pricePoolPerShare(PoolId poolId, ShareClassId scId) public view returns (D18 price) {\n ISyncDepositValuation valuation_ = valuation[poolId][scId];\n\n if (address(valuation_) == address(0)) {\n price = poolManager.pricePoolPerShare(poolId, scId, true);\n } else {\n price = valuation_.pricePoolPerShare(poolId, scId);\n }\n }\n\n /// @inheritdoc ISyncRequestManager\n function prices(PoolId poolId, ShareClassId scId, AssetId assetId) public view returns (Prices memory priceData) {\n priceData.poolPerShare = pricePoolPerShare(poolId, scId);\n priceData.poolPerAsset = poolManager.pricePoolPerAsset(poolId, scId, assetId, true);\n priceData.assetPerShare = PricingLib.priceAssetPerShare(priceData.poolPerShare, priceData.poolPerAsset);\n }\n\n //----------------------------------------------------------------------------------------------\n // Internal\n //----------------------------------------------------------------------------------------------\n\n /// @dev Issues shares to the receiver and instruct the balance sheet\n // to react on the issuance and the updated holding.\n function _issueShares(IBaseVault vault_, uint128 shares, address receiver, address, /* owner */ uint128 assets)\n internal\n {\n PoolId poolId = vault_.poolId();\n ShareClassId scId = vault_.scId();\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n\n balanceSheet.overridePricePoolPerShare(poolId, scId, prices(poolId, scId, vaultDetails.assetId).poolPerShare);\n balanceSheet.issue(poolId, scId, receiver, shares);\n\n // Note deposit into the pool escrow, to make assets available for managers of the balance sheet\n // ERC-20 transfer is handled by the vault to the pool escrow afterwards\n balanceSheet.noteDeposit(poolId, scId, vaultDetails.asset, vaultDetails.tokenId, receiver, assets);\n }\n\n function _maxDeposit(PoolId poolId, ShareClassId scId, address asset, uint256 tokenId)\n internal\n view\n returns (uint128 maxDeposit_)\n {\n uint128 availableBalance = poolEscrowProvider.escrow(poolId).availableBalanceOf(scId, asset, tokenId);\n uint128 maxReserve_ = maxReserve[poolId][scId][asset][tokenId];\n\n if (maxReserve_ < availableBalance) {\n maxDeposit_ = 0;\n } else {\n maxDeposit_ = maxReserve_ - availableBalance;\n }\n }\n\n function _shareToAssetAmount(IBaseVault vault_, uint256 assets, MathLib.Rounding rounding)\n internal\n view\n returns (uint256 shares)\n {\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n Prices memory prices_ = prices(vault_.poolId(), vault_.scId(), vaultDetails.assetId);\n return super._shareToAssetAmount(\n vault_, vaultDetails, assets, prices_.poolPerAsset, prices_.poolPerShare, rounding\n );\n }\n}\n" + }, + "src/vaults/VaultRouter.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {Multicall, IMulticall} from \"src/misc/Multicall.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {SafeTransferLib} from \"src/misc/libraries/SafeTransferLib.sol\";\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {IERC20, IERC20Permit, IERC20Wrapper} from \"src/misc/interfaces/IERC20.sol\";\nimport {IERC7540Deposit} from \"src/misc/interfaces/IERC7540.sol\";\nimport {Recoverable} from \"src/misc/Recoverable.sol\";\n\nimport {IGateway} from \"src/common/interfaces/IGateway.sol\";\nimport {IMessageDispatcher} from \"src/common/interfaces/IMessageDispatcher.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nimport {IAsyncVault, IBaseVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\nimport {IVaultRouter} from \"src/vaults/interfaces/IVaultRouter.sol\";\nimport {IPoolManager, VaultDetails} from \"src/vaults/interfaces/IPoolManager.sol\";\nimport {IEscrow} from \"src/vaults/interfaces/IEscrow.sol\";\nimport {BaseSyncDepositVault} from \"src/vaults/BaseVaults.sol\";\n\n/// @title VaultRouter\n/// @notice This is a helper contract, designed to be the entrypoint for EOAs.\n/// It removes the need to know about all other contracts and simplifies the way to interact with the protocol.\n/// It also adds the need to fully pay for each step of the transaction execution. VaultRouter allows\n/// the caller to execute multiple function into a single transaction by taking advantage of\n/// the multicall functionality which batches message calls into a single one.\n/// @dev It is critical to ensure that at the end of any transaction, no funds remain in the\n/// VaultRouter. Any funds that do remain are at risk of being taken by other users.\ncontract VaultRouter is Auth, Multicall, Recoverable, IVaultRouter {\n using CastLib for address;\n\n /// @dev Requests for Centrifuge pool are non-fungible and all have ID = 0\n uint256 private constant REQUEST_ID = 0;\n\n IEscrow public immutable escrow;\n IGateway public immutable gateway;\n IPoolManager public immutable poolManager;\n IMessageDispatcher public immutable messageDispatcher;\n\n /// @inheritdoc IVaultRouter\n mapping(address controller => mapping(IBaseVault vault => uint256 amount)) public lockedRequests;\n\n constructor(\n address escrow_,\n IGateway gateway_,\n IPoolManager poolManager_,\n IMessageDispatcher messageDispatcher_,\n address deployer\n ) Auth(deployer) {\n escrow = IEscrow(escrow_);\n gateway = gateway_;\n poolManager = poolManager_;\n messageDispatcher = messageDispatcher_;\n }\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IMulticall\n /// @notice performs a multicall but all message sent in the process will be batched\n function multicall(bytes[] calldata data) public payable override(Multicall, IMulticall) {\n bool wasBatching = gateway.isBatching();\n if (!wasBatching) {\n gateway.startBatching();\n gateway.payTransaction{value: msg.value}(msg.sender);\n }\n\n super.multicall(data);\n\n if (!wasBatching) {\n gateway.endBatching();\n }\n }\n\n //----------------------------------------------------------------------------------------------\n // Enable interactions\n //----------------------------------------------------------------------------------------------\n\n function enable(IBaseVault vault) public payable protected {\n vault.setEndorsedOperator(msg.sender, true);\n }\n\n function disable(IBaseVault vault) external payable protected {\n vault.setEndorsedOperator(msg.sender, false);\n }\n\n //----------------------------------------------------------------------------------------------\n // Deposit\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IVaultRouter\n function requestDeposit(IAsyncVault vault, uint256 amount, address controller, address owner)\n external\n payable\n protected\n {\n require(owner == msg.sender || owner == address(this), InvalidOwner());\n\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault);\n if (owner == address(this)) {\n _approveMax(vaultDetails.asset, address(vault));\n }\n\n _pay();\n vault.requestDeposit(amount, controller, owner);\n }\n\n /// @inheritdoc IVaultRouter\n function deposit(BaseSyncDepositVault vault, uint256 assets, address receiver, address owner)\n external\n payable\n protected\n {\n require(owner == msg.sender || owner == address(this), InvalidOwner());\n require(!vault.supportsInterface(type(IERC7540Deposit).interfaceId), NonSyncDepositVault());\n\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault);\n SafeTransferLib.safeTransferFrom(vaultDetails.asset, owner, address(this), assets);\n _approveMax(vaultDetails.asset, address(vault));\n\n _pay();\n vault.deposit(assets, receiver);\n }\n\n /// @inheritdoc IVaultRouter\n function lockDepositRequest(IBaseVault vault, uint256 amount, address controller, address owner)\n public\n payable\n protected\n {\n require(owner == msg.sender || owner == address(this), InvalidOwner());\n require(vault.supportsInterface(type(IERC7540Deposit).interfaceId), NonAsyncVault());\n\n lockedRequests[controller][vault] += amount;\n\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault);\n SafeTransferLib.safeTransferFrom(vaultDetails.asset, owner, address(escrow), amount);\n\n emit LockDepositRequest(vault, controller, owner, msg.sender, amount);\n }\n\n /// @inheritdoc IVaultRouter\n function enableLockDepositRequest(IBaseVault vault, uint256 amount) external payable protected {\n enable(vault);\n\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault);\n\n uint256 assetBalance;\n assetBalance = IERC20(vaultDetails.asset).balanceOf(msg.sender);\n\n if (vaultDetails.isWrapper && assetBalance < amount) {\n wrap(vaultDetails.asset, amount, address(this), msg.sender);\n lockDepositRequest(vault, amount, msg.sender, address(this));\n } else {\n lockDepositRequest(vault, amount, msg.sender, msg.sender);\n }\n }\n\n /// @inheritdoc IVaultRouter\n function unlockDepositRequest(IBaseVault vault, address receiver) external payable protected {\n uint256 lockedRequest = lockedRequests[msg.sender][vault];\n require(lockedRequest != 0, NoLockedBalance());\n lockedRequests[msg.sender][vault] = 0;\n\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault);\n escrow.authTransferTo(vaultDetails.asset, receiver, lockedRequest);\n\n emit UnlockDepositRequest(vault, msg.sender, receiver);\n }\n\n /// @inheritdoc IVaultRouter\n function executeLockedDepositRequest(IAsyncVault vault, address controller) external payable protected {\n uint256 lockedRequest = lockedRequests[controller][vault];\n require(lockedRequest != 0, NoLockedRequest());\n lockedRequests[controller][vault] = 0;\n\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault);\n escrow.authTransferTo(vaultDetails.asset, address(this), lockedRequest);\n\n _pay();\n _approveMax(vaultDetails.asset, address(vault));\n vault.requestDeposit(lockedRequest, controller, address(this));\n emit ExecuteLockedDepositRequest(vault, controller, msg.sender);\n }\n\n /// @inheritdoc IVaultRouter\n function claimDeposit(IAsyncVault vault, address receiver, address controller) external payable protected {\n _canClaim(vault, receiver, controller);\n uint256 maxMint = vault.maxMint(controller);\n vault.mint(maxMint, receiver, controller);\n }\n\n /// @inheritdoc IVaultRouter\n function cancelDepositRequest(IAsyncVault vault) external payable protected {\n _pay();\n vault.cancelDepositRequest(REQUEST_ID, msg.sender);\n }\n\n /// @inheritdoc IVaultRouter\n function claimCancelDepositRequest(IAsyncVault vault, address receiver, address controller)\n external\n payable\n protected\n {\n _canClaim(vault, receiver, controller);\n vault.claimCancelDepositRequest(REQUEST_ID, receiver, controller);\n }\n\n //----------------------------------------------------------------------------------------------\n // Redeem\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IVaultRouter\n function requestRedeem(IAsyncVault vault, uint256 amount, address controller, address owner)\n external\n payable\n protected\n {\n require(owner == msg.sender || owner == address(this), InvalidOwner());\n _pay();\n vault.requestRedeem(amount, controller, owner);\n }\n\n /// @inheritdoc IVaultRouter\n function claimRedeem(IBaseVault vault, address receiver, address controller) external payable protected {\n _canClaim(vault, receiver, controller);\n uint256 maxWithdraw = vault.maxWithdraw(controller);\n\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault);\n if (vaultDetails.isWrapper && controller != msg.sender) {\n // Auto-unwrap if permissionlessly claiming for another controller\n vault.withdraw(maxWithdraw, address(this), controller);\n unwrap(vaultDetails.asset, maxWithdraw, receiver);\n } else {\n vault.withdraw(maxWithdraw, receiver, controller);\n }\n }\n\n /// @inheritdoc IVaultRouter\n function cancelRedeemRequest(IAsyncVault vault) external payable protected {\n _pay();\n vault.cancelRedeemRequest(REQUEST_ID, msg.sender);\n }\n\n /// @inheritdoc IVaultRouter\n function claimCancelRedeemRequest(IAsyncVault vault, address receiver, address controller)\n external\n payable\n protected\n {\n _canClaim(vault, receiver, controller);\n vault.claimCancelRedeemRequest(REQUEST_ID, receiver, controller);\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-20 permits & wrapping\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IVaultRouter\n function permit(address asset, address spender, uint256 assets, uint256 deadline, uint8 v, bytes32 r, bytes32 s)\n external\n payable\n protected\n {\n try IERC20Permit(asset).permit(msg.sender, spender, assets, deadline, v, r, s) {} catch {}\n }\n\n function wrap(address wrapper, uint256 amount, address receiver, address owner) public payable protected {\n require(owner == msg.sender || owner == address(this), InvalidOwner());\n address underlying = IERC20Wrapper(wrapper).underlying();\n\n amount = MathLib.min(amount, IERC20(underlying).balanceOf(owner));\n require(amount != 0, ZeroBalance());\n SafeTransferLib.safeTransferFrom(underlying, owner, address(this), amount);\n\n _approveMax(underlying, wrapper);\n require(IERC20Wrapper(wrapper).depositFor(receiver, amount), WrapFailed());\n }\n\n function unwrap(address wrapper, uint256 amount, address receiver) public payable protected {\n amount = MathLib.min(amount, IERC20(wrapper).balanceOf(address(this)));\n require(amount != 0, ZeroBalance());\n\n require(IERC20Wrapper(wrapper).withdrawTo(receiver, amount), UnwrapFailed());\n }\n\n //----------------------------------------------------------------------------------------------\n // View methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IVaultRouter\n function getVault(PoolId poolId, ShareClassId scId, address asset) external view returns (address) {\n return IPoolManager(poolManager).shareToken(poolId, scId).vault(asset);\n }\n\n /// @inheritdoc IVaultRouter\n function estimate(uint16 centrifugeId, bytes calldata payload) external view returns (uint256) {\n return messageDispatcher.estimate(centrifugeId, payload);\n }\n\n /// @inheritdoc IVaultRouter\n function hasPermissions(IBaseVault vault, address controller) external view returns (bool) {\n return vault.isPermissioned(controller);\n }\n\n /// @inheritdoc IVaultRouter\n function isEnabled(IBaseVault vault, address controller) public view returns (bool) {\n return vault.isOperator(controller, address(this));\n }\n\n /// @notice Gives the max approval to `to` for spending the given `asset` if not already approved.\n /// @dev Assumes that `type(uint256).max` is large enough to never have to increase the allowance again.\n function _approveMax(address asset, address spender) internal {\n if (IERC20(asset).allowance(address(this), spender) == 0) {\n SafeTransferLib.safeApprove(asset, spender, type(uint256).max);\n }\n }\n\n /// @notice Send native tokens to the gateway for transaction payment if it's not in a multicall.\n function _pay() internal {\n if (!gateway.isBatching()) {\n gateway.payTransaction{value: msg.value}(msg.sender);\n }\n }\n\n /// @notice Ensures msg.sender is either the controller, or can permissionlessly claim\n /// on behalf of the controller.\n function _canClaim(IBaseVault vault, address receiver, address controller) internal view {\n require(controller == msg.sender || (controller == receiver && isEnabled(vault, controller)), InvalidSender());\n }\n}\n" + }, + "src/vaults/factories/AsyncVaultFactory.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nimport {AsyncVault} from \"src/vaults/AsyncVault.sol\";\nimport {IVaultFactory} from \"src/vaults/interfaces/factories/IVaultFactory.sol\";\nimport {IPoolEscrowProvider} from \"src/vaults/interfaces/factories/IPoolEscrowFactory.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\nimport {IAsyncRequestManager} from \"src/vaults/interfaces/investments/IAsyncRequestManager.sol\";\nimport {IBaseVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\n\n/// @title ERC7540 Vault Factory\n/// @dev Utility for deploying new vault contracts\ncontract AsyncVaultFactory is Auth, IVaultFactory {\n address public immutable root;\n IAsyncRequestManager public immutable asyncRequestManager;\n\n constructor(address root_, IAsyncRequestManager asyncRequestManager_, address deployer) Auth(deployer) {\n root = root_;\n asyncRequestManager = asyncRequestManager_;\n }\n\n /// @inheritdoc IVaultFactory\n function newVault(\n PoolId poolId,\n ShareClassId scId,\n address asset,\n uint256 tokenId,\n IShareToken token,\n address[] calldata wards_\n ) public auth returns (IBaseVault) {\n require(tokenId == 0, UnsupportedTokenId());\n AsyncVault vault = new AsyncVault(poolId, scId, asset, token, root, asyncRequestManager);\n\n vault.rely(root);\n vault.rely(address(asyncRequestManager));\n uint256 wardsCount = wards_.length;\n for (uint256 i; i < wardsCount; i++) {\n vault.rely(wards_[i]);\n }\n\n vault.deny(address(this));\n return vault;\n }\n}\n" + }, + "src/vaults/factories/PoolEscrowFactory.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\n\nimport {IPoolEscrowProvider, IPoolEscrowFactory} from \"src/vaults/interfaces/factories/IPoolEscrowFactory.sol\";\nimport {IPoolEscrow} from \"src/vaults/interfaces/IEscrow.sol\";\nimport {PoolEscrow} from \"src/vaults/Escrow.sol\";\n\ncontract PoolEscrowFactory is Auth, IPoolEscrowFactory {\n address public immutable root;\n\n address public gateway;\n address public poolManager;\n address public balanceSheet;\n address public asyncRequestManager;\n\n constructor(address root_, address deployer) Auth(deployer) {\n root = root_;\n }\n\n /// @inheritdoc IPoolEscrowFactory\n function file(bytes32 what, address data) external auth {\n if (what == \"poolManager\") poolManager = data;\n else if (what == \"gateway\") gateway = data;\n else if (what == \"balanceSheet\") balanceSheet = data;\n else if (what == \"asyncRequestManager\") asyncRequestManager = data;\n else revert FileUnrecognizedParam();\n emit File(what, data);\n }\n\n /// @inheritdoc IPoolEscrowFactory\n function newEscrow(PoolId poolId) public auth returns (IPoolEscrow) {\n PoolEscrow escrow_ = new PoolEscrow{salt: bytes32(uint256(poolId.raw()))}(poolId, address(this));\n\n escrow_.rely(root);\n escrow_.rely(gateway);\n escrow_.rely(poolManager);\n escrow_.rely(balanceSheet);\n escrow_.rely(asyncRequestManager);\n\n escrow_.deny(address(this));\n\n emit DeployPoolEscrow(poolId, address(escrow_));\n return IPoolEscrow(escrow_);\n }\n\n /// @inheritdoc IPoolEscrowProvider\n function escrow(PoolId poolId) external view returns (IPoolEscrow) {\n bytes32 salt = bytes32(uint256(poolId.raw()));\n bytes32 hash = keccak256(\n abi.encodePacked(\n bytes1(0xff),\n address(this),\n salt,\n keccak256(abi.encodePacked(type(PoolEscrow).creationCode, abi.encode(poolId, address(this))))\n )\n );\n\n return IPoolEscrow(address(uint160(uint256(hash))));\n }\n}\n" + }, + "src/vaults/factories/SyncDepositVaultFactory.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nimport {SyncDepositVault} from \"src/vaults/SyncDepositVault.sol\";\nimport {IVaultFactory} from \"src/vaults/interfaces/factories/IVaultFactory.sol\";\nimport {IAsyncRedeemManager} from \"src/vaults/interfaces/investments/IAsyncRedeemManager.sol\";\nimport {ISyncDepositManager} from \"src/vaults/interfaces/investments/ISyncDepositManager.sol\";\nimport {IPoolEscrowProvider} from \"src/vaults/interfaces/factories/IPoolEscrowFactory.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\nimport {IBaseVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\n\n/// @title Sync Vault Factory\n/// @dev Utility for deploying new vault contracts\ncontract SyncDepositVaultFactory is Auth, IVaultFactory {\n address public immutable root;\n ISyncDepositManager public immutable syncDepositManager;\n IAsyncRedeemManager public immutable asyncRedeemManager;\n\n constructor(\n address root_,\n ISyncDepositManager syncDepositManager_,\n IAsyncRedeemManager asyncRedeemManager_,\n address deployer\n ) Auth(deployer) {\n root = root_;\n syncDepositManager = syncDepositManager_;\n asyncRedeemManager = asyncRedeemManager_;\n }\n\n /// @inheritdoc IVaultFactory\n function newVault(\n PoolId poolId,\n ShareClassId scId,\n address asset,\n uint256 tokenId,\n IShareToken token,\n address[] calldata wards_\n ) public auth returns (IBaseVault) {\n require(tokenId == 0, UnsupportedTokenId());\n SyncDepositVault vault =\n new SyncDepositVault(poolId, scId, asset, token, root, syncDepositManager, asyncRedeemManager);\n\n vault.rely(root);\n vault.rely(address(syncDepositManager));\n vault.rely(address(asyncRedeemManager));\n\n uint256 wardsCount = wards_.length;\n for (uint256 i; i < wardsCount; i++) {\n vault.rely(wards_[i]);\n }\n\n vault.deny(address(this));\n return vault;\n }\n}\n" + }, + "src/vaults/factories/TokenFactory.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\n\nimport {ShareToken} from \"src/vaults/token/ShareToken.sol\";\nimport {ITokenFactory} from \"src/vaults/interfaces/factories/ITokenFactory.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\n\n/// @title Share Token Factory\n/// @dev Utility for deploying new share class token contracts\n/// Ensures the addresses are deployed at a deterministic address\n/// based on the pool id and share class id.\ncontract TokenFactory is Auth, ITokenFactory {\n address public immutable root;\n\n constructor(address _root, address deployer) Auth(deployer) {\n root = _root;\n }\n\n /// @inheritdoc ITokenFactory\n function newToken(\n string memory name,\n string memory symbol,\n uint8 decimals,\n bytes32 salt,\n address[] calldata tokenWards\n ) public auth returns (IShareToken) {\n ShareToken token = new ShareToken{salt: salt}(decimals);\n\n token.file(\"name\", name);\n token.file(\"symbol\", symbol);\n\n token.rely(root);\n uint256 wardsCount = tokenWards.length;\n for (uint256 i; i < wardsCount; i++) {\n token.rely(tokenWards[i]);\n }\n token.deny(address(this));\n\n return token;\n }\n\n /// @inheritdoc ITokenFactory\n function getAddress(uint8 decimals, bytes32 salt) external view returns (address) {\n bytes32 hash = keccak256(\n abi.encodePacked(\n bytes1(0xff),\n address(this),\n salt,\n keccak256(abi.encodePacked(type(ShareToken).creationCode, abi.encode(decimals)))\n )\n );\n\n return address(uint160(uint256(hash)));\n }\n}\n" + }, + "src/vaults/interfaces/IBalanceSheet.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {D18, d18} from \"src/misc/types/D18.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\n\nstruct QueueAmount {\n // Issuances of shares / deposits of assets\n uint128 increase;\n // Revocations of shares / withdraws of assets\n uint128 decrease;\n}\n\ninterface IBalanceSheet {\n // --- Events ---\n event File(bytes32 indexed what, address data);\n event UpdateManager(PoolId indexed poolId, address who, bool canManage);\n event Withdraw(\n PoolId indexed poolId,\n ShareClassId indexed scId,\n address asset,\n uint256 tokenId,\n address receiver,\n uint128 amount,\n D18 pricePoolPerAsset\n );\n event Deposit(\n PoolId indexed poolId,\n ShareClassId indexed scId,\n address asset,\n uint256 tokenId,\n address provider,\n uint128 amount,\n D18 pricePoolPerAsset\n );\n event Issue(PoolId indexed poolId, ShareClassId indexed scId, address to, D18 pricePoolPerShare, uint128 shares);\n event Revoke(PoolId indexed poolId, ShareClassId indexed scId, address from, D18 pricePoolPerShare, uint128 shares);\n\n // --- Errors ---\n error FileUnrecognizedParam();\n error CannotTransferFromEndorsedContract();\n\n /// @notice Overloaded increase with asset transfer\n function deposit(PoolId poolId, ShareClassId scId, address asset, uint256 tokenId, address provider, uint128 amount)\n external;\n\n function noteDeposit(\n PoolId poolId,\n ShareClassId scId,\n address asset,\n uint256 tokenId,\n address provider,\n uint128 amount\n ) external;\n\n function withdraw(\n PoolId poolId,\n ShareClassId scId,\n address asset,\n uint256 tokenId,\n address receiver,\n uint128 amount\n ) external;\n\n function issue(PoolId poolId, ShareClassId scId, address to, uint128 shares) external;\n\n function revoke(PoolId poolId, ShareClassId scId, address from, uint128 shares) external;\n\n function noteRevoke(PoolId poolId, ShareClassId scId, address from, uint128 shares) external;\n\n function transferSharesFrom(PoolId poolId, ShareClassId scId, address from, address to, uint256 amount) external;\n\n function overridePricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId, D18 value) external;\n\n function overridePricePoolPerShare(PoolId poolId, ShareClassId scId, D18 value) external;\n}\n" + }, + "src/vaults/interfaces/IBaseVaults.sol": { + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.5.0;\n\nenum VaultKind {\n /// @dev Refers to AsyncVault\n Async,\n /// @dev not yet supported\n Sync,\n /// @dev Refers to SyncDepositVault\n SyncDepositAsyncRedeem\n}\n\nimport {IERC7575, IERC165} from \"src/misc/interfaces/IERC7575.sol\";\nimport {\n IERC7540Operator,\n IERC7714,\n IERC7741,\n IERC7540Redeem,\n IERC7887Redeem,\n IERC7887Deposit,\n IERC7540Deposit\n} from \"src/misc/interfaces/IERC7540.sol\";\nimport {IRecoverable} from \"src/misc/interfaces/IRecoverable.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nimport {IBaseRequestManager} from \"src/vaults/interfaces/investments/IBaseRequestManager.sol\";\nimport {IAsyncRedeemManager} from \"src/vaults/interfaces/investments/IAsyncRedeemManager.sol\";\n\n/// @notice Interface for the all vault contracts\n/// @dev Must be implemented by all vaults\ninterface IBaseVault is IERC7540Operator, IERC7741, IERC7714, IERC7575, IRecoverable {\n error FileUnrecognizedParam();\n error NotEndorsed();\n error CannotSetSelfAsOperator();\n error ExpiredAuthorization();\n error AlreadyUsedAuthorization();\n error InvalidAuthorization();\n error InvalidController();\n error InsufficientBalance();\n error RequestRedeemFailed();\n error TransferFromFailed();\n\n event File(bytes32 indexed what, address data);\n\n /// @notice Identifier of the Centrifuge pool\n function poolId() external view returns (PoolId);\n\n /// @notice Identifier of the share class of the Centrifuge pool\n function scId() external view returns (ShareClassId);\n\n /// @notice Set msg.sender as operator of owner, to `approved` status\n /// @dev MUST be called by endorsed sender\n function setEndorsedOperator(address owner, bool approved) external;\n\n /// @notice Returns the base investment manager contract handling the vault.\n /// @dev This naming MUST NOT change due to requirements of legacy vaults (v2)\n /// @return IBaseRequestManager The address of the manager contract that is between vault and gateway\n function manager() external view returns (IBaseRequestManager);\n\n /// @notice Checks whether the vault is partially (a)synchronous.\n ///\n /// @return vaultKind_ The kind of the vault\n function vaultKind() external view returns (VaultKind vaultKind_);\n}\n\n/**\n * @title IAsyncRedeemVault\n * @dev This is the specific set of interfaces used by the Centrifuge implementation of ERC7540,\n * as a fully asynchronous Vault, with cancellation support, and authorize operator signature support.\n */\ninterface IAsyncRedeemVault is IERC7540Redeem, IERC7887Redeem, IBaseVault {\n event RedeemClaimable(address indexed controller, uint256 indexed requestId, uint256 assets, uint256 shares);\n event CancelRedeemClaimable(address indexed controller, uint256 indexed requestId, uint256 shares);\n\n /// @notice Callback when a redeem Request is triggered externally;\n function onRedeemRequest(address controller, address owner, uint256 shares) external;\n\n /// @notice Callback when a redeem Request becomes claimable\n function onRedeemClaimable(address owner, uint256 assets, uint256 shares) external;\n\n /// @notice Callback when a claim redeem Request becomes claimable\n function onCancelRedeemClaimable(address owner, uint256 shares) external;\n\n /// @notice Retrieve the asynchronous redeem manager\n function asyncRedeemManager() external view returns (IAsyncRedeemManager);\n}\n\ninterface IAsyncVault is IERC7540Deposit, IERC7887Deposit, IAsyncRedeemVault {\n event DepositClaimable(address indexed controller, uint256 indexed requestId, uint256 assets, uint256 shares);\n event CancelDepositClaimable(address indexed controller, uint256 indexed requestId, uint256 assets);\n\n error InvalidOwner();\n error RequestDepositFailed();\n\n /// @notice Callback when a deposit Request becomes claimable\n function onDepositClaimable(address owner, uint256 assets, uint256 shares) external;\n\n /// @notice Callback when a claim deposit Request becomes claimable\n function onCancelDepositClaimable(address owner, uint256 assets) external;\n}\n" + }, + "src/vaults/interfaces/IEscrow.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IRecoverable} from \"src/misc/Recoverable.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\n/// @title Escrow for holding assets\ninterface IEscrow {\n // --- Events ---\n /// @notice Emitted when an authTransferTo is made\n /// @dev Needed as allowances increase attack surface\n event AuthTransferTo(address indexed asset, uint256 indexed tokenId, address reciver, uint256 value);\n\n /// @notice Emitted when the escrow has insufficient balance for an action - virtual or actual balance\n error InsufficientBalance(address asset, uint256 tokenId, uint256 value, uint256 balance);\n\n /// @notice\n function authTransferTo(address asset, uint256 tokenId, address receiver, uint256 value) external;\n\n /// @notice\n function authTransferTo(address asset, address receiver, uint256 value) external;\n}\n\nstruct Holding {\n uint128 total;\n uint128 reserved;\n}\n\n/// @title PerPoolEscrow separating funds by pool and share class\ninterface IPoolEscrow is IEscrow, IRecoverable {\n // --- Events ---\n /// @notice Emitted when a deposit is made\n /// @param asset The address of the deposited asset\n /// @param tokenId The id of the asset - 0 for ERC20\n /// @param poolId The id of the pool\n /// @param scId The id of the share class\n /// @param value The amount deposited\n event Deposit(\n address indexed asset, uint256 indexed tokenId, PoolId indexed poolId, ShareClassId scId, uint128 value\n );\n\n /// @notice Emitted when an amount is reserved\n /// @param asset The address of the reserved asset\n /// @param tokenId The id of the asset - 0 for ERC20\n /// @param poolId The id of the pool\n /// @param scId The id of the share class\n /// @param value The delta amount reserved\n /// @param value The new absolute amount reserved\n event IncreaseReserve(\n address indexed asset,\n uint256 indexed tokenId,\n PoolId indexed poolId,\n ShareClassId scId,\n uint256 delta,\n uint128 value\n );\n\n /// @notice Emitted when an amount is unreserved\n /// @param asset The address of the reserved asset\n /// @param tokenId The id of the asset - 0 for ERC20\n /// @param poolId The id of the pool\n /// @param scId The id of the share class\n /// @param value The delta amount unreserved\n /// @param value The new absolute amount reserved\n event DecreaseReserve(\n address indexed asset,\n uint256 indexed tokenId,\n PoolId indexed poolId,\n ShareClassId scId,\n uint256 delta,\n uint128 value\n );\n\n /// @notice Emitted when a withdraw is made\n /// @param asset The address of the withdrawn asset\n /// @param tokenId The id of the asset - 0 for ERC20\n /// @param poolId The id of the pool\n /// @param scId The id of the share class\n /// @param value The amount withdrawn\n event Withdraw(\n address indexed asset, uint256 indexed tokenId, PoolId indexed poolId, ShareClassId scId, uint128 value\n );\n\n // --- Errors ---\n /// @notice Dispatched when the balance of the escrow did not increase sufficiently\n error InsufficientDeposit();\n\n /// @notice Dispatched when the outstanding reserved amount is insufficient for the decrease\n error InsufficientReservedAmount();\n\n // --- Functions ---\n /// @notice Deposits `value` of `asset` in underlying `poolId` and given `scId`\n ///\n /// @dev NOTE: Must ensure balance sufficiency, i.e. that the depositing amount does not exceed the balance of\n /// escrow\n ///\n /// @param scId The id of the share class\n /// @param asset The address of the asset to be deposited\n /// @param tokenId The id of the asset - 0 for ERC20\n /// @param value The amount to deposit\n function deposit(ShareClassId scId, address asset, uint256 tokenId, uint128 value) external;\n\n /// @notice Withdraws `value` of `asset` in underlying `poolId` and given `scId`\n /// @dev MUST ensure that reserved amounts are not withdrawn\n /// @param scId The id of the share class\n /// @param asset The address of the asset to be withdrawn\n /// @param tokenId The id of the asset - 0 for ERC20\n /// @param value The amount to withdraw\n function withdraw(ShareClassId scId, address asset, uint256 tokenId, uint128 value) external;\n\n /// @notice Increases the reserved amount of `value` for `asset` in underlying `poolId` and given `scId`\n /// @dev MUST prevent the reserved amount from being withdrawn\n /// @param scId The id of the share class\n /// @param asset The address of the asset to be reserved\n /// @param tokenId The id of the asset - 0 for ERC20\n /// @param value The amount to reserve\n function reserveIncrease(ShareClassId scId, address asset, uint256 tokenId, uint128 value) external;\n\n /// @notice Decreases the reserved amount of `value` for `asset` in underlying `poolId` and given `scId`\n /// @dev MUST fail if `value` is greater than the current reserved amount\n /// @param scId The id of the share class\n /// @param asset The address of the asset to be reserved\n /// @param tokenId The id of the asset - 0 for ERC20\n /// @param value The amount to decrease\n function reserveDecrease(ShareClassId scId, address asset, uint256 tokenId, uint128 value) external;\n\n /// @notice Provides the available balance of `asset` in underlying `poolId` and given `scId`\n /// @dev MUST return the balance minus the reserved amount\n /// @param scId The id of the share class\n /// @param asset The address of the asset to be checked\n /// @param tokenId The id of the asset - 0 for ERC20\n /// @return The available balance\n function availableBalanceOf(ShareClassId scId, address asset, uint256 tokenId) external view returns (uint128);\n}\n" + }, + "src/vaults/interfaces/IPoolManager.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {D18, d18} from \"src/misc/types/D18.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\n\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\nimport {IVaultFactory} from \"src/vaults/interfaces/factories/IVaultFactory.sol\";\nimport {IBaseVault, VaultKind} from \"src/vaults/interfaces/IBaseVaults.sol\";\n\n/// @dev Centrifuge pools\nstruct Pool {\n uint256 createdAt;\n mapping(ShareClassId scId => ShareClassDetails) shareClasses;\n}\n\n/// @dev Each Centrifuge pool is associated to 1 or more shar classes\nstruct ShareClassDetails {\n IShareToken shareToken;\n /// @dev Each share class has an individual price per share class unit in pool denomination (POOL_UNIT/SHARE_UNIT)\n Price pricePoolPerShare;\n /// @dev Each share class can have multiple vaults deployed,\n /// multiple vaults can be linked to the same asset.\n /// A vault in this storage DOES NOT mean the vault can be used\n mapping(address asset => mapping(uint256 tokenId => IBaseVault[])) vaults;\n /// @dev For each share class, we store the price per pool unit in asset denomination (POOL_UNIT/ASSET_UNIT)\n mapping(address asset => mapping(uint256 tokenId => Price)) pricePoolPerAsset;\n}\n\n/// @dev Price struct that contains a price, the timestamp at which it was computed and the max age of the price.\nstruct Price {\n uint128 price;\n uint64 computedAt;\n uint64 maxAge;\n}\n\n/// @dev Checks if a price is valid. Returns false if price is 0 or computedAt is 0. Otherwise checks for block\n/// timestamp <= computedAt + maxAge\nfunction isValid(Price memory price) view returns (bool) {\n if (price.computedAt != 0 && price.price != 0) {\n return block.timestamp <= price.validUntil();\n } else {\n return false;\n }\n}\n\n/// @dev Computes the timestamp until the price is valid. Saturates at uint64.MAX.\nfunction validUntil(Price memory price) pure returns (uint64) {\n unchecked {\n uint64 validUntil_ = price.computedAt + price.maxAge;\n if (validUntil_ < price.computedAt) {\n return type(uint64).max;\n }\n return validUntil_;\n }\n}\n\n/// @dev Retrieves the price as an D18 from the struct\nfunction asPrice(Price memory price) pure returns (D18) {\n return d18(price.price);\n}\n\nusing {isValid, asPrice, validUntil} for Price global;\n\nstruct VaultDetails {\n /// @dev AssetId of the asset\n AssetId assetId;\n /// @dev Address of the asset\n address asset;\n /// @dev TokenId of the asset - zero if asset is ERC20, non-zero if asset is ERC6909\n uint256 tokenId;\n /// @dev Whether this wrapper conforms to the IERC20Wrapper interface\n bool isWrapper;\n /// @dev Whether the vault is linked to a share class atm\n bool isLinked;\n}\n\nstruct AssetIdKey {\n /// @dev The address of the asset\n address asset;\n /// @dev The ERC6909 token id or 0, if the underlying asset is an ERC20\n uint256 tokenId;\n}\n\ninterface IPoolManager {\n event File(bytes32 indexed what, address data);\n event RegisterAsset(\n AssetId indexed assetId,\n address indexed asset,\n uint256 indexed tokenId,\n string name,\n string symbol,\n uint8 decimals\n );\n event File(bytes32 indexed what, address factory, bool status);\n event AddPool(PoolId indexed poolId);\n event AddShareClass(PoolId indexed poolId, ShareClassId indexed scId, IShareToken token);\n event DeployVault(\n PoolId indexed poolId,\n ShareClassId indexed scId,\n address indexed asset,\n uint256 tokenId,\n IVaultFactory factory,\n IBaseVault vault,\n VaultKind kind\n );\n event PriceUpdate(\n PoolId indexed poolId,\n ShareClassId indexed scId,\n address indexed asset,\n uint256 tokenId,\n uint256 price,\n uint64 computedAt\n );\n event PriceUpdate(PoolId indexed poolId, ShareClassId indexed scId, uint256 price, uint64 computedAt);\n event TransferShares(\n uint16 centrifugeId,\n PoolId indexed poolId,\n ShareClassId indexed scId,\n address indexed sender,\n bytes32 destinationAddress,\n uint128 amount\n );\n event UpdateContract(PoolId indexed poolId, ShareClassId indexed scId, address target, bytes payload);\n event LinkVault(\n PoolId indexed poolId, ShareClassId indexed scId, address indexed asset, uint256 tokenId, IBaseVault vault\n );\n event UnlinkVault(\n PoolId indexed poolId, ShareClassId indexed scId, address indexed asset, uint256 tokenId, IBaseVault vault\n );\n event UpdateMaxSharePriceAge(PoolId indexed poolId, ShareClassId indexed scId, uint64 maxPriceAge);\n event UpdateMaxAssetPriceAge(\n PoolId indexed poolId, ShareClassId indexed scId, address indexed asset, uint256 tokenId, uint64 maxPriceAge\n );\n\n error FileUnrecognizedParam();\n error TooFewDecimals();\n error TooManyDecimals();\n error PoolAlreadyAdded();\n error InvalidPool();\n error ShareClassAlreadyRegistered();\n error InvalidHook();\n error OldMetadata();\n error CannotSetOlderPrice();\n error OldHook();\n error UnknownVault();\n error UnknownAsset();\n error MalformedVaultUpdateMessage();\n error UnknownToken();\n error InvalidFactory();\n error InvalidPrice();\n error AssetMissingDecimals();\n error ShareTokenDoesNotExist();\n error LocalTransferNotAllowed();\n error CrossChainTransferNotAllowed();\n error ShareTokenTransferFailed();\n error TransferFromFailed();\n\n /// @notice Returns the asset address and tokenId associated with a given asset id.\n /// @dev Reverts if asset id does not exist\n ///\n /// @param assetId The underlying internal uint128 assetId.\n /// @return asset The address of the asset linked to the given asset id.\n /// @return tokenId The token id corresponding to the asset, i.e. zero if ERC20 or non-zero if ERC6909.\n function idToAsset(AssetId assetId) external view returns (address asset, uint256 tokenId);\n\n /// @notice Returns assetId given the asset address and tokenId.\n /// @dev Reverts if asset id does not exist\n ///\n /// @param asset The address of the asset linked to the given asset id.\n /// @param tokenId The token id corresponding to the asset, i.e. zero if ERC20 or non-zero if ERC6909.\n /// @return assetId The underlying internal uint128 assetId.\n function assetToId(address asset, uint256 tokenId) external view returns (AssetId assetId);\n\n /// @notice Updates a contract parameter\n /// @param what Accepts a bytes32 representation of 'gateway', 'investmentManager', 'tokenFactory',\n /// 'vaultFactory', or 'gasService'\n function file(bytes32 what, address data) external;\n\n /// @notice Updates a contract parameter\n /// @param what Accepts a bytes32 representation of 'vaultFactory'\n function file(bytes32 what, address factory, bool status) external;\n\n /// @notice transfers share class tokens to a cross-chain recipient address\n /// @dev To transfer to evm chains, pad a 20 byte evm address with 12 bytes of 0\n /// @param centrifugeId The destination chain id\n /// @param poolId The centrifuge pool id\n /// @param scId The share class id\n /// @param receiver A bytes32 representation of the receiver address\n /// @param amount The amount of tokens to transfer\n function transferShares(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bytes32 receiver, uint128 amount)\n external\n payable;\n\n /// @notice Registers an ERC-20 or ERC-6909 asset in another chain.\n /// @dev `decimals()` MUST return a `uint8` value between 2 and 18.\n /// @dev `name()` and `symbol()` MAY return no values.\n ///\n /// @param centrifugeId The centrifuge id of chain to where the shares are transferred\n /// @param asset The address of the asset to be registered\n /// @param tokenId The token id corresponding to the asset, i.e. zero if ERC20 or non-zero if ERC6909.\n /// @return assetId The underlying internal uint128 assetId.\n function registerAsset(uint16 centrifugeId, address asset, uint256 tokenId)\n external\n payable\n returns (AssetId assetId);\n\n /// @notice Deploys a new vault\n ///\n /// @param poolId The pool id\n /// @param scId The share class id\n /// @param assetId The asset id for which we want to deploy a vault\n /// @param factory The address of the corresponding vault factory\n /// @return address The address of the deployed vault\n function deployVault(PoolId poolId, ShareClassId scId, AssetId assetId, IVaultFactory factory)\n external\n returns (IBaseVault);\n\n /// @notice Links a deployed vault to the given pool, share class and asset.\n ///\n /// @param poolId The pool id\n /// @param scId The share class id\n /// @param assetId The asset id for which we want to deploy a vault\n /// @param vault The address of the deployed vault\n function linkVault(PoolId poolId, ShareClassId scId, AssetId assetId, IBaseVault vault) external;\n\n /// @notice Removes the link between a vault and the given pool, share class and asset.\n ///\n /// @param poolId The pool id\n /// @param scId The share class id\n /// @param assetId The asset id for which we want to deploy a vault\n /// @param vault The address of the deployed vault\n function unlinkVault(PoolId poolId, ShareClassId scId, AssetId assetId, IBaseVault vault) external;\n\n /// @notice Returns whether the given pool id is active\n function isPoolActive(PoolId poolId) external view returns (bool);\n\n /// @notice Returns the share class token for a given pool and share class id.\n /// @dev Reverts if share class does not exists\n ///\n /// @param poolId The pool id\n /// @param scId The share class id\n /// @return address The address of the share token\n function shareToken(PoolId poolId, ShareClassId scId) external view returns (IShareToken);\n\n /// @notice Function to get the details of a vault\n /// @dev Reverts if vault does not exist\n ///\n /// @param vault The address of the vault to be checked for\n /// @return details The details of the vault including the underlying asset address, token id, asset id\n function vaultDetails(IBaseVault vault) external view returns (VaultDetails memory details);\n\n /// @notice Checks whether a given asset-vault pair is eligible for investing into a share class of a pool\n ///\n /// @param poolId The pool id\n /// @param scId The share class id\n /// @param asset The address of the asset\n /// @param vault The address of the vault\n /// @return bool Whether vault is to a share class\n function isLinked(PoolId poolId, ShareClassId scId, address asset, IBaseVault vault) external view returns (bool);\n\n /// @notice Returns the price per share for a given pool, share class, asset, and asset id. The provided price is\n /// defined as ASSET_UNIT/SHARE_UNIT.\n /// @dev Conditionally checks if price is valid.\n ///\n /// @dev NOTE: Should never be used for calculating amounts due to precision loss. Instead, please refer to\n /// conversion relying on pricePoolPerShare and pricePoolPerAsset. See PricingLib for more information.\n ///\n /// @param poolId The pool id\n /// @param scId The share class id\n /// @param assetId The asset id for which we want to know the ASSET_UNIT/SHARE_UNIT price\n /// @param checkValidity Whether to check if the price is valid\n /// @return price The asset price per share\n function priceAssetPerShare(PoolId poolId, ShareClassId scId, AssetId assetId, bool checkValidity)\n external\n view\n returns (D18 price);\n\n /// @notice Returns the price per share for a given pool and share class. The Provided price is defined as\n /// POOL_UNIT/SHARE_UNIT.\n /// @dev Conditionally checks if price is valid.\n ///\n /// @param poolId The pool id\n /// @param scId The share class id\n /// @param checkValidity Whether to check if the price is valid\n /// @return price The pool price per share\n function pricePoolPerShare(PoolId poolId, ShareClassId scId, bool checkValidity)\n external\n view\n returns (D18 price);\n\n /// @notice Returns the price per asset for a given pool, share class and the underlying asset id. The Provided\n /// price is defined as POOL_UNIT/ASSET_UNIT.\n /// @dev Conditionally checks if price is valid.\n ///\n /// @param poolId The pool id\n /// @param scId The share class id\n /// @param assetId The asset id for which we want to know the POOL_UNIT/ASSET_UNIT.\n /// @param checkValidity Whether to check if the price is valid\n /// @return price The pool price per asset unit\n function pricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId, bool checkValidity)\n external\n view\n returns (D18 price);\n\n /// @notice Returns the both prices per pool for a given pool, share class and the underlying asset id. The Provided\n /// prices is defined as POOL_UNIT/ASSET_UNIT and POOL_UNIT/SHARE_UNIT.\n /// @dev Conditionally checks if prices are valid.\n ///\n /// @param poolId The pool id\n /// @param scId The share class id\n /// @param assetId The asset id for which we want to know pool price per asset\n /// @param checkValidity Whether to check if the prices are valid\n /// @return pricePoolPerAsset The pool price per asset unit, i.e. POOL_UNIT/ASSET_UNIT\n /// @return pricePoolPerShare The pool price per share unit, i.e. POOL_UNIT/SHARE_UNIT\n function pricesPoolPer(PoolId poolId, ShareClassId scId, AssetId assetId, bool checkValidity)\n external\n view\n returns (D18 pricePoolPerAsset, D18 pricePoolPerShare);\n\n /// @notice Returns the age related markers for a share class price\n ///\n /// @param poolId The pool id\n /// @param scId The share class id\n /// @return computedAt The timestamp when this price was computed\n /// @return maxAge The maximum age this price is allowed to have\n /// @return validUntil The timestamp until this price is valid\n function markersPricePoolPerShare(PoolId poolId, ShareClassId scId)\n external\n view\n returns (uint64 computedAt, uint64 maxAge, uint64 validUntil);\n\n /// @notice Returns the age related markers for an asset price\n ///\n /// @param poolId The pool id\n /// @param scId The share class id\n /// @param assetId The asset id for which we want to know pool price per asset\n /// @return computedAt The timestamp when this price was computed\n /// @return maxAge The maximum age this price is allowed to have\n /// @return validUntil The timestamp until this price is valid\n function markersPricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId)\n external\n view\n returns (uint64 computedAt, uint64 maxAge, uint64 validUntil);\n}\n" + }, + "src/vaults/interfaces/IUpdateContract.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\n\ninterface IUpdateContract {\n error UnknownUpdateContractType();\n\n /// @notice Triggers an update on the target contract.\n /// @param poolId The centrifuge pool id\n /// @param scId The share class id\n /// @param payload The payload to be processed by the target address\n function update(PoolId poolId, ShareClassId scId, bytes calldata payload) external;\n}\n" + }, + "src/vaults/interfaces/IVaultRouter.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IMulticall} from \"src/misc/interfaces/IMulticall.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {IBaseVault, IAsyncVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\nimport {BaseSyncDepositVault} from \"src/vaults/BaseVaults.sol\";\n\ninterface IVaultRouter is IMulticall {\n // --- Events ---\n event LockDepositRequest(\n IBaseVault indexed vault, address indexed controller, address indexed owner, address sender, uint256 amount\n );\n event UnlockDepositRequest(IBaseVault indexed vault, address indexed controller, address indexed receiver);\n event ExecuteLockedDepositRequest(IBaseVault indexed vault, address indexed controller, address sender);\n\n error InvalidOwner();\n error NoLockedBalance();\n error NoLockedRequest();\n error ZeroBalance();\n error WrapFailed();\n error UnwrapFailed();\n error InvalidSender();\n error NonSyncDepositVault();\n error NonAsyncVault();\n\n /// @notice Check how much of the `vault`'s asset is locked for the current `controller`.\n /// @dev This is a getter method\n function lockedRequests(address controller, IBaseVault vault) external view returns (uint256 amount);\n\n // --- Manage permissionless claiming ---\n /// @notice Enable permissionless claiming\n /// @dev After this is called, anyone can claim tokens to msg.sender.\n /// Even any requests submitted directly to the vault (not through the VaultRouter) will be\n /// permissionlessly claimable through the VaultRouter, until `disable()` is called.\n function enable(IBaseVault vault) external payable;\n\n /// @notice Disable permissionless claiming\n function disable(IBaseVault vault) external payable;\n\n // --- Deposit ---\n /// @notice Check `IERC7540Deposit.requestDeposit`.\n /// @dev This adds a mandatory prepayment for all the costs that will incur during the transaction.\n /// The caller must call `VaultRouter.estimate` to get estimates how much the deposit will cost.\n ///\n /// @param vault The vault to deposit into\n /// @param amount Check @param IERC7540Deposit.requestDeposit.assets\n /// @param controller Check @param IERC7540Deposit.requestDeposit.controller\n /// @param owner Check @param IERC7540Deposit.requestDeposit.owner\n function requestDeposit(IAsyncVault vault, uint256 amount, address controller, address owner) external payable;\n\n /// @notice Check `IERC4626.deposit`.\n /// @dev This adds a mandatory prepayment for all the costs that will incur during the transaction.\n /// The caller must call `VaultRouter.estimate` to get estimates how much the deposit will cost.\n ///\n /// @param vault The vault to deposit into\n /// @param assets Check @param IERC4626.deposit.assets\n /// @param receiver Check @param IERC4626.deposit.receiver\n /// @param owner User from which to transfer the assets, either msg.sender or the VaultRouter\n function deposit(BaseSyncDepositVault vault, uint256 assets, address receiver, address owner) external payable;\n\n /// @notice Locks `amount` of `vault`'s asset in an escrow before actually sending a deposit LockDepositRequest\n /// There are users that would like to interact with the protocol but don't have permissions yet. They can\n /// lock the funds they would like to deposit beforehand.\n /// Once permissions are granted, anyone can deposit on\n /// their behalf by calling `executeLockedDepositRequest`.\n ///\n /// Example: DAO with onchain governance, that wants to invest their treasury\n /// The process that doesn't include calling this method is as follows:\n ///\n /// 1. The DAO signs the legal agreements for the pool => no onchain action,\n /// but only after this the issuer can call update_member to add them as a whitelisted investor\n /// 2. Call `requestDeposit` to lock funds\n /// 3. After the pool has fulfilled their request, call `deposit` to claim their share class tokens\n ///\n ///\n /// With the new router function the steps are as follows:\n ///\n /// 1. DAO signs the legal agreement + calls `openLockDepositRequest` in 1 governance proposal\n ///\n /// 2. Issuer then gives them permissions, then calls `executeLockDepositFunds` for them,\n /// then fulfills the request, then calls `claimDeposit` for them\n ///\n /// @dev For initial interaction better use `openLockDepositRequest` which includes some of the message calls\n /// that the caller must do execute before calling `lockDepositRequest`\n ///\n /// @param vault The address of the vault to invest in\n /// @param amount Amount to invest\n /// @param controller Address of the owner of the position\n /// @param owner Where the funds to be deposited will be take from\n function lockDepositRequest(IBaseVault vault, uint256 amount, address controller, address owner) external payable;\n\n /// @notice Helper method to lock a deposit request, and enable permissionless claiming of that vault in 1 call.\n /// @dev It starts interaction with the vault by calling `open`.\n /// Vaults support assets that are wrapped one. When user calls this method\n /// and the vault's asset is a wrapped one, first the balance of the wrapped asset is checked.\n /// If balance >= `amount`, then this asset is used\n /// else amount is treat as an underlying asset one and it is wrapped.\n /// @param vault Address of the vault\n /// @param amount Amount to be deposited\n function enableLockDepositRequest(IBaseVault vault, uint256 amount) external payable;\n\n /// @notice Unlocks all deposited assets of the current caller for a given vault\n ///\n /// @param vault Address of the vault for which funds were locked\n /// @param receiver Address of the received of the unlocked funds\n function unlockDepositRequest(IBaseVault vault, address receiver) external payable;\n\n /// @notice After the controller is given permissions, anyone can call this method and\n /// actually request a deposit with the locked funds on the behalf of the `controller`\n /// @param vault The vault for which funds are locked\n /// @param controller Owner of the deposit position\n function executeLockedDepositRequest(IAsyncVault vault, address controller) external payable;\n\n /// @notice Check IERC7540Deposit.mint\n /// @param vault Address of the vault\n /// @param receiver Check IERC7540Deposit.mint.receiver\n /// @param controller Check IERC7540Deposit.mint.owner\n function claimDeposit(IAsyncVault vault, address receiver, address controller) external payable;\n\n // --- Redeem ---\n /// @notice Check `IERC7887Deposit.cancelDepositRequest`.\n /// @dev This adds a mandatory prepayment for all the costs that will incur during the transaction.\n /// The caller must call `VaultRouter.estimate` to get estimates how much the deposit will cost.\n ///\n /// @param vault The vault where the deposit was initiated\n function cancelDepositRequest(IAsyncVault vault) external payable;\n\n /// @notice Check IERC7887Deposit.claimCancelDepositRequest\n ///\n /// @param vault Address of the vault\n /// @param receiver Check IERC7887Deposit.claimCancelDepositRequest.receiver\n /// @param controller Check IERC7887Deposit.claimCancelDepositRequest.controller\n function claimCancelDepositRequest(IAsyncVault vault, address receiver, address controller) external payable;\n\n // --- Redeem ---\n /// @notice Check `IERC7540Redeem.requestRedeem`.\n /// @dev This adds a mandatory prepayment for all the costs that will incur during the transaction.\n /// The caller must call `VaultRouter.estimate` to get estimates how much the deposit will cost.\n ///\n /// @param vault The vault to deposit into\n /// @param amount Check @param IERC7540Redeem.requestRedeem.shares\n /// @param controller Check @param IERC7540Redeem.requestRedeem.controller\n /// @param owner Check @param IERC7540Redeem.requestRedeem.owner\n function requestRedeem(IAsyncVault vault, uint256 amount, address controller, address owner) external payable;\n\n /// @notice Check IERC7575.withdraw\n /// @dev If the underlying vault asset is a wrapped one,\n /// `VaultRouter.unwrap` is called and the unwrapped\n /// asset is sent to the receiver\n /// @param vault Address of the vault\n /// @param receiver Check IERC7575.withdraw.receiver\n /// @param controller Check IERC7575.withdraw.owner\n function claimRedeem(IBaseVault vault, address receiver, address controller) external payable;\n\n /// @notice Check `IERC7887Redeem.cancelRedeemRequest`.\n /// @dev This adds a mandatory prepayment for all the costs that will incur during the transaction.\n /// The caller must call `VaultRouter.estimate` to get estimates how much the deposit will cost.\n ///\n /// @param vault The vault where the deposit was initiated\n function cancelRedeemRequest(IAsyncVault vault) external payable;\n\n /// @notice Check IERC7887Redeem.claimableCancelRedeemRequest\n ///\n /// @param vault Address of the vault\n /// @param receiver Check IERC7887Redeem.claimCancelRedeemRequest.receiver\n /// @param controller Check IERC7887Redeem.claimCancelRedeemRequest.controller\n function claimCancelRedeemRequest(IAsyncVault vault, address receiver, address controller) external payable;\n\n // --- ERC20 permit ---\n /// @notice Check IERC20.permit\n function permit(address asset, address spender, uint256 assets, uint256 deadline, uint8 v, bytes32 r, bytes32 s)\n external\n payable;\n\n // --- ERC20 wrapping ---\n /// @notice There are vault which underlying asset is actuall a wrapped one.\n ///\n /// @param wrapper The address of the wrapper\n /// @param amount Amount to be wrapped\n /// @param receiver Receiver of the wrapped tokens\n /// @param owner The address from which `amount` is taken from\n function wrap(address wrapper, uint256 amount, address receiver, address owner) external payable;\n\n /// @notice There are vault which underlying asset is actuall a wrapped one.\n /// @dev Wrapped tokens need to be held by the VaultRouter to be unwrapped.\n /// @param wrapper The address of the wrapper\n /// @param amount Amount to be wrapped\n /// @param receiver Receiver of the unwrapped tokens\n function unwrap(address wrapper, uint256 amount, address receiver) external payable;\n\n // --- View Methods ---\n /// @notice Check IPoolManager.getVault\n function getVault(PoolId poolId, ShareClassId scId, address asset) external view returns (address);\n\n /// @notice Check IGateway.estimate\n /// If the destination and source chain ID are the same, this will always return 0.\n /// @param centrifugeId destination chain\n function estimate(uint16 centrifugeId, bytes calldata payload) external view returns (uint256 amount);\n\n /// @notice Called to check if `user` has permissions on `vault` to execute requests\n ///\n /// @param vault Address of the `vault` the `user` wants to operate on\n /// @param user Address of the `user` that will operates on the `vault`\n /// @return Whether `user` has permissions to operate on `vault`\n function hasPermissions(IBaseVault vault, address user) external view returns (bool);\n\n /// @notice Returns whether the controller has called `enable()` for the given `vault`\n function isEnabled(IBaseVault vault, address controller) external view returns (bool);\n}\n" + }, + "src/vaults/interfaces/factories/IPoolEscrowFactory.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\n\nimport {IPoolEscrow} from \"src/vaults/interfaces/IEscrow.sol\";\n\ninterface IPoolEscrowProvider {\n /// @notice Returns the deterministic address of an escrow contract based on a given pool id wrapped into the\n /// corresponding interface.\n ///\n /// @dev Does not check, whether the escrow was already deployed.\n function escrow(PoolId poolId) external view returns (IPoolEscrow);\n}\n\ninterface IPoolEscrowFactory is IPoolEscrowProvider {\n event DeployPoolEscrow(PoolId indexed poolId, address indexed escrow);\n event File(bytes32 what, address data);\n\n error FileUnrecognizedParam();\n error EscrowAlreadyDeployed();\n\n /// @notice Deploys new escrow and returns it.\n /// @dev All share classes of a pool are represented by the same escrow contract.\n ///\n /// @param poolId Id of the pool this escrow is deployed for\n /// @return IPoolEscrow The the newly deployed escrow contract\n function newEscrow(PoolId poolId) external returns (IPoolEscrow);\n\n /// @notice Updates contract parameters of type address.\n function file(bytes32 what, address data) external;\n}\n" + }, + "src/vaults/interfaces/factories/ITokenFactory.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\n\ninterface ITokenFactory {\n /// @notice Used to deploy new share class tokens.\n /// @dev In order to have the same address on different EVMs `salt` should be used\n /// during creationg process.\n /// @param name Name of the new token.\n /// @param symbol Symbol of the new token.\n /// @param decimals Decimals of the new token.\n /// @param salt Salt used for deterministic deployments.\n /// @param tokenWards Address which can call methods behind authorized only.\n function newToken(\n string memory name,\n string memory symbol,\n uint8 decimals,\n bytes32 salt,\n address[] calldata tokenWards\n ) external returns (IShareToken);\n\n /// @notice Returns the predicted address (using CREATE2)\n function getAddress(uint8 decimals, bytes32 salt) external view returns (address);\n}\n" + }, + "src/vaults/interfaces/factories/IVaultFactory.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\nimport {IPoolEscrow} from \"src/vaults/interfaces/IEscrow.sol\";\nimport {IBaseVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\n\ninterface IVaultFactory {\n error UnsupportedTokenId();\n\n /// @notice Deploys new vault for `poolId`, `scId` and `asset`.\n ///\n /// @param poolId Id of the pool. Id is one of the already supported pools.\n /// @param scId Id of the share class token. Id is one of the already supported share class tokens.\n /// @param asset Address of the underlying asset that is getting deposited inside the pool.\n /// @param asset Token id of the underlying asset that is getting deposited inside the pool. I.e. zero if asset\n /// corresponds to ERC20 or non-zero if asset corresponds to ERC6909.\n /// @param token Address of the share class token that is getting issues against the deposited asset.\n /// @param wards_ Address which can call methods behind authorized only.\n function newVault(\n PoolId poolId,\n ShareClassId scId,\n address asset,\n uint256 tokenId,\n IShareToken token,\n address[] calldata wards_\n ) external returns (IBaseVault);\n}\n" + }, + "src/vaults/interfaces/investments/IAsyncDepositManager.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IDepositManager} from \"src/vaults/interfaces/investments/IDepositManager.sol\";\nimport {IBaseVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\n\ninterface IAsyncDepositManager is IDepositManager {\n /// @notice Requests assets deposit. Vaults have to request investments from Centrifuge before\n /// shares can be minted. The deposit requests are added to the order book\n /// on the corresponding CP instance. Once the next epoch is executed on the corresponding CP instance,\n /// vaults can\n /// proceed with share payouts in case the order got fulfilled.\n /// @dev The assets required to fulfill the deposit request have to be locked and are transferred from the\n /// owner to the escrow, even though the share payout can only happen after epoch execution.\n /// The receiver becomes the owner of deposit request fulfillment.\n /// @param source Deprecated\n function requestDeposit(IBaseVault vault, uint256 assets, address receiver, address owner, address source)\n external\n returns (bool);\n\n /// @notice Requests the cancellation of a pending deposit request. Vaults have to request the\n /// cancellation of outstanding requests from Centrifuge before actual assets can be unlocked and\n /// transferred\n /// to the owner.\n /// While users have outstanding cancellation requests no new deposit requests can be submitted.\n /// Once the next epoch is executed on the corresponding CP instance, vaults can proceed with asset payouts\n /// if orders could be cancelled successfully.\n /// @dev The cancellation request might fail in case the pending deposit order already got fulfilled on\n /// Centrifuge.\n /// @param source Deprecated\n function cancelDepositRequest(IBaseVault vault, address owner, address source) external;\n\n /// @notice Processes owner's deposit request cancellation after the epoch has been executed on the corresponding CP\n /// instance and the\n /// deposit order cancellation has been successfully processed (partial fulfillment possible).\n /// Assets are transferred from the escrow to the receiver.\n /// @dev The assets required to fulfill the claim have already been reserved for the owner in escrow on\n /// fulfillCancelDepositRequest.\n function claimCancelDepositRequest(IBaseVault vault, address receiver, address owner)\n external\n returns (uint256 assets);\n\n /// @notice Indicates whether a user has pending deposit requests and returns the total deposit request asset\n /// request value.\n function pendingDepositRequest(IBaseVault vault, address user) external view returns (uint256 assets);\n\n /// @notice Indicates whether a user has pending deposit request cancellations.\n function pendingCancelDepositRequest(IBaseVault vault, address user) external view returns (bool isPending);\n\n /// @notice Indicates whether a user has claimable deposit request cancellation and returns the total claim\n /// value in assets.\n function claimableCancelDepositRequest(IBaseVault vault, address user) external view returns (uint256 assets);\n}\n" + }, + "src/vaults/interfaces/investments/IAsyncRedeemManager.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IRedeemManager} from \"src/vaults/interfaces/investments/IRedeemManager.sol\";\nimport {IBaseVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\n\ninterface IAsyncRedeemManager is IRedeemManager {\n /// @notice Requests share redemption. Vaults have to request redemptions\n /// from Centrifuge before actual asset payouts can be done. The redemption\n /// requests are added to the order book on the corresponding CP instance. Once the next epoch is\n /// executed on the corresponding CP instance, vaults can proceed with asset payouts\n /// in case the order got fulfilled.\n /// @dev The shares required to fulfill the redemption request have to be locked and are transferred from the\n /// owner to the escrow, even though the asset payout can only happen after epoch execution.\n /// The receiver becomes the owner of redeem request fulfillment.\n /// @param source Deprecated\n function requestRedeem(IBaseVault vault, uint256 shares, address receiver, address owner, address source)\n external\n returns (bool);\n\n /// @notice Requests the cancellation of an pending redeem request. Vaults have to request the\n /// cancellation of outstanding requests from Centrifuge before actual shares can be unlocked and\n /// transferred to the owner.\n /// While users have outstanding cancellation requests no new redeem requests can be submitted (exception:\n /// trigger through governance).\n /// Once the next epoch is executed on the corresponding CP instance, vaults can proceed with share payouts\n /// if the orders could be cancelled successfully.\n /// @dev The cancellation request might fail in case the pending redeem order already got fulfilled on\n /// Centrifuge.\n function cancelRedeemRequest(IBaseVault vault, address owner, address source) external;\n\n /// @notice Processes owner's redeem request cancellation after the epoch has been executed on the corresponding CP\n /// instance and the\n /// redeem order cancellation has been successfully processed (partial fulfillment possible).\n /// Shares are transferred from the escrow to the receiver.\n /// @dev The shares required to fulfill the claim have already been reserved for the owner in escrow on\n /// fulfillCancelRedeemRequest.\n /// Receiver has to pass all the share token restrictions in order to receive the shares.\n function claimCancelRedeemRequest(IBaseVault vault, address receiver, address owner)\n external\n returns (uint256 shares);\n\n /// @notice Indicates whether a user has pending redeem requests and returns the total share request value.\n function pendingRedeemRequest(IBaseVault vault, address user) external view returns (uint256 shares);\n\n /// @notice Indicates whether a user has pending redeem request cancellations.\n function pendingCancelRedeemRequest(IBaseVault vault, address user) external view returns (bool isPending);\n\n /// @notice Indicates whether a user has claimable redeem request cancellation and returns the total claim\n /// value in shares.\n function claimableCancelRedeemRequest(IBaseVault vault, address user) external view returns (uint256 shares);\n}\n" + }, + "src/vaults/interfaces/investments/IAsyncRequestManager.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IRequestManagerGatewayHandler} from \"src/common/interfaces/IGatewayHandlers.sol\";\n\nimport {IAsyncDepositManager} from \"src/vaults/interfaces/investments/IAsyncDepositManager.sol\";\nimport {IAsyncRedeemManager} from \"src/vaults/interfaces/investments/IAsyncRedeemManager.sol\";\nimport {IBaseVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\n\n/// @dev Vault requests and deposit/redeem bookkeeping per user\nstruct AsyncInvestmentState {\n /// @dev Shares that can be claimed using `mint()`\n uint128 maxMint;\n /// @dev Assets that can be claimed using `withdraw()`\n uint128 maxWithdraw;\n /// @dev Weighted average price of deposits, used to convert maxMint to maxDeposit\n /// @dev Represents priceAssetPerShare, i.e. ASSET_UNIT/SHARE_UNIT\n uint256 depositPrice;\n /// @dev Weighted average price of redemptions, used to convert maxWithdraw to maxRedeem\n /// @dev Represents priceAssetPerShare, i.e. ASSET_UNIT/SHARE_UNIT\n uint256 redeemPrice;\n /// @dev Remaining deposit request in assets\n uint128 pendingDepositRequest;\n /// @dev Remaining redeem request in shares\n uint128 pendingRedeemRequest;\n /// @dev Assets that can be claimed using `claimCancelDepositRequest()`\n uint128 claimableCancelDepositRequest;\n /// @dev Shares that can be claimed using `claimCancelRedeemRequest()`\n uint128 claimableCancelRedeemRequest;\n /// @dev Indicates whether the depositRequest was requested to be cancelled\n bool pendingCancelDepositRequest;\n /// @dev Indicates whether the redeemRequest was requested to be cancelled\n bool pendingCancelRedeemRequest;\n}\n\ninterface IAsyncRequestManager is IAsyncDepositManager, IAsyncRedeemManager, IRequestManagerGatewayHandler {\n error ZeroAmountNotAllowed();\n error TransferNotAllowed();\n error CancellationIsPending();\n error NoPendingRequest();\n error ShareTokenAmountIsZero();\n error FailedRedeemRequest();\n error ExceedsDepositLimits();\n error ShareTokenTransferFailed();\n error ExceedsMaxRedeem();\n error ExceedsRedeemLimits();\n\n /// @notice Returns the investment state\n function investments(IBaseVault vaultAddr, address investor)\n external\n view\n returns (\n uint128 maxMint,\n uint128 maxWithdraw,\n uint256 depositPrice,\n uint256 redeemPrice,\n uint128 pendingDepositRequest,\n uint128 pendingRedeemRequest,\n uint128 claimableCancelDepositRequest,\n uint128 claimableCancelRedeemRequest,\n bool pendingCancelDepositRequest,\n bool pendingCancelRedeemRequest\n );\n}\n" + }, + "src/vaults/interfaces/investments/IBaseRequestManager.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\n\nimport {IPoolManager} from \"src/vaults/interfaces/IPoolManager.sol\";\nimport {IBaseVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\nimport {IPoolEscrow, IEscrow} from \"src/vaults/interfaces/IEscrow.sol\";\n\ninterface IBaseRequestManager {\n // --- Events ---\n event File(bytes32 indexed what, address data);\n\n error FileUnrecognizedParam();\n error SenderNotVault();\n error AssetNotAllowed();\n error ExceedsMaxDeposit();\n error AssetMismatch();\n error VaultAlreadyExists();\n error VaultDoesNotExist();\n\n /// @notice Updates contract parameters of type address.\n /// @param what The bytes32 representation of 'gateway' or 'poolManager'.\n /// @param data The new contract address.\n function file(bytes32 what, address data) external;\n\n /// @notice Converts the assets value to share decimals.\n function convertToShares(IBaseVault vault, uint256 _assets) external view returns (uint256 shares);\n\n /// @notice Converts the shares value to assets decimals.\n function convertToAssets(IBaseVault vault, uint256 _shares) external view returns (uint256 assets);\n\n /// @notice Returns the timestamp of the last share price update for a vaultAddr.\n function priceLastUpdated(IBaseVault vault) external view returns (uint64 lastUpdated);\n\n /// @notice Returns the PoolManager contract address.\n function poolManager() external view returns (IPoolManager poolManager);\n\n /// @notice The global escrow used for funds that are not yet free to be used for a specific pool\n function globalEscrow() external view returns (IEscrow escrow);\n\n /// @notice Escrow per pool. Funds are associated to a specific pool\n function poolEscrow(PoolId poolId) external view returns (IPoolEscrow);\n\n /// @notice Adds new vault for `poolId`, `scId` and `asset`.\n function addVault(PoolId poolId, ShareClassId scId, IBaseVault vault, address asset, AssetId assetId) external;\n\n /// @notice Removes `vault` from `who`'s authorized callers\n function removeVault(PoolId poolId, ShareClassId scId, IBaseVault vault, address asset, AssetId assetId) external;\n\n /// @notice Returns the address of the vault for a given pool, share class and asset\n function vaultByAssetId(PoolId poolId, ShareClassId scId, AssetId assetId)\n external\n view\n returns (IBaseVault vault);\n}\n" + }, + "src/vaults/interfaces/investments/IDepositManager.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IBaseRequestManager} from \"src/vaults/interfaces/investments/IBaseRequestManager.sol\";\nimport {IBaseVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\n\ninterface IDepositManager is IBaseRequestManager {\n /// @notice Processes owner's asset deposit after the epoch has been executed on the corresponding CP instance and\n /// the deposit order\n /// has been successfully processed (partial fulfillment possible).\n /// Shares are transferred from the escrow to the receiver. Amount of shares is computed based of the amount\n /// of assets and the owner's share price.\n /// @dev The assets required to fulfill the deposit are already locked in escrow upon calling requestDeposit.\n /// The shares required to fulfill the deposit have already been minted and transferred to the escrow on\n /// fulfillDepositRequest.\n /// Receiver has to pass all the share token restrictions in order to receive the shares.\n function deposit(IBaseVault vault, uint256 assets, address receiver, address owner)\n external\n returns (uint256 shares);\n\n /// @notice Processes owner's share mint after the epoch has been executed on the corresponding CP instance and the\n /// deposit order has\n /// been successfully processed (partial fulfillment possible).\n /// Shares are transferred from the escrow to the receiver. Amount of assets is computed based of the amount\n /// of shares and the owner's share price.\n /// @dev The assets required to fulfill the mint are already locked in escrow upon calling requestDeposit.\n /// The shares required to fulfill the mint have already been minted and transferred to the escrow on\n /// fulfillDepositRequest.\n /// Receiver has to pass all the share token restrictions in order to receive the shares.\n function mint(IBaseVault vault, uint256 shares, address receiver, address owner)\n external\n returns (uint256 assets);\n\n /// @notice Returns the max amount of assets based on the unclaimed amount of shares after at least one successful\n /// deposit order fulfillment on the corresponding CP instance.\n function maxDeposit(IBaseVault vault, address user) external view returns (uint256);\n\n /// @notice Returns the max amount of shares a user can claim after at least one successful deposit order\n /// fulfillment on the corresponding CP instance.\n function maxMint(IBaseVault vault, address user) external view returns (uint256 shares);\n}\n" + }, + "src/vaults/interfaces/investments/IRedeemManager.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IBaseRequestManager} from \"src/vaults/interfaces/investments/IBaseRequestManager.sol\";\nimport {IBaseVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\n\ninterface IRedeemManager is IBaseRequestManager {\n event TriggerRedeemRequest(\n uint64 indexed poolId,\n bytes16 indexed scId,\n address user,\n address indexed asset,\n uint256 tokenId,\n uint128 shares\n );\n\n /// @notice Processes owner's share redemption after the epoch has been executed on the corresponding CP instance\n /// and the redeem order\n /// has been successfully processed (partial fulfillment possible).\n /// Assets are transferred from the escrow to the receiver. Amount of assets is computed based of the amount\n /// of shares and the owner's share price.\n /// @dev The shares required to fulfill the redemption were already locked in escrow on requestRedeem and burned\n /// on fulfillRedeemRequest.\n /// The assets required to fulfill the redemption have already been reserved in escrow on\n /// fulfillRedeemtRequest.\n function redeem(IBaseVault vault, uint256 shares, address receiver, address owner)\n external\n returns (uint256 assets);\n\n /// @notice Processes owner's asset withdrawal after the epoch has been executed on the corresponding CP instance\n /// and the redeem order\n /// has been successfully processed (partial fulfillment possible).\n /// Assets are transferred from the escrow to the receiver. Amount of shares is computed based of the amount\n /// of shares and the owner's share price.\n /// @dev The shares required to fulfill the withdrawal were already locked in escrow on requestRedeem and burned\n /// on fulfillRedeemRequest.\n /// The assets required to fulfill the withdrawal have already been reserved in escrow on\n /// fulfillRedeemtRequest.\n function withdraw(IBaseVault vault, uint256 assets, address receiver, address owner)\n external\n returns (uint256 shares);\n\n /// @notice Returns the max amount of shares based on the unclaimed number of assets after at least one successful\n /// redeem order fulfillment on the corresponding CP instance.\n function maxRedeem(IBaseVault vault, address user) external view returns (uint256 shares);\n\n /// @notice Returns the max amount of assets a user can claim after at least one successful redeem order fulfillment\n /// on the corresponding CP instance.\n function maxWithdraw(IBaseVault vault, address user) external view returns (uint256 assets);\n}\n" + }, + "src/vaults/interfaces/investments/ISyncDepositManager.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IDepositManager} from \"src/vaults/interfaces/investments/IDepositManager.sol\";\nimport {IBaseVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\n\ninterface ISyncDepositManager is IDepositManager {\n function previewDeposit(IBaseVault vault, address sender, uint256 assets) external view returns (uint256);\n function previewMint(IBaseVault vault, address sender, uint256 shares) external view returns (uint256);\n}\n" + }, + "src/vaults/interfaces/investments/ISyncRequestManager.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {D18} from \"src/misc/types/D18.sol\";\n\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nimport {IUpdateContract} from \"src/vaults/interfaces/IUpdateContract.sol\";\nimport {ISyncDepositManager} from \"src/vaults/interfaces/investments/ISyncDepositManager.sol\";\n\n/// @dev Solely used locally as protection against stack-too-deep\nstruct Prices {\n /// @dev Price of 1 asset unit per share unit\n D18 assetPerShare;\n /// @dev Price of 1 pool unit per asset unit\n D18 poolPerAsset;\n /// @dev Price of 1 pool unit per share unit\n D18 poolPerShare;\n}\n\ninterface ISyncDepositValuation {\n /// @notice Returns the pool price per share for a given pool and share class, asset, and asset id.\n // The provided price is defined as POOL_UNIT/SHARE_UNIT.\n ///\n /// @param poolId The pool id\n /// @param scId The share class id\n /// @return price The pool price per share\n function pricePoolPerShare(PoolId poolId, ShareClassId scId) external view returns (D18 price);\n}\n\ninterface ISyncRequestManager is ISyncDepositManager, ISyncDepositValuation, IUpdateContract {\n event SetValuation(PoolId indexed poolId, ShareClassId indexed scId, address valuation);\n event SetMaxReserve(\n PoolId indexed poolId, ShareClassId indexed scId, address asset, uint256 tokenId, uint128 maxReserve\n );\n\n error ExceedsMaxMint();\n error ShareTokenDoesNotExist();\n error SecondaryManagerDoesNotExist();\n\n /// @notice Sets the valuation for a specific pool and share class.\n ///\n /// @param poolId The id of the pool\n /// @param scId The id of the share class\n /// @param valuation The address of the valuation contract\n function setValuation(PoolId poolId, ShareClassId scId, address valuation) external;\n\n /// @notice Sets the max reserve for a specific pool, share class and asset.\n ///\n /// @param poolId The id of the pool\n /// @param scId The id of the share class\n /// @param asset The address of the asset\n /// @param tokenId The asset token id, i.e. 0 for ERC20, or the token id for ERC6909\n /// @param maxReserve The amount of maximum reserve\n function setMaxReserve(PoolId poolId, ShareClassId scId, address asset, uint256 tokenId, uint128 maxReserve)\n external;\n\n /// @notice Returns the all three prices for a given pool, share class, asset, and asset id.\n ///\n /// @param poolId The pool id\n /// @param scId The share class id\n /// @param assetId The asset id corresponding to the asset and tokenId\n /// @return priceData The asset price per share, pool price per asset, and pool price per share\n function prices(PoolId poolId, ShareClassId scId, AssetId assetId)\n external\n view\n returns (Prices memory priceData);\n}\n" + }, + "src/vaults/interfaces/token/IShareToken.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IERC20Metadata} from \"src/misc/interfaces/IERC20.sol\";\nimport {IERC7575Share} from \"src/misc/interfaces/IERC7575.sol\";\n\ninterface IERC1404 {\n /// @notice Detects if a transfer will be reverted and if so returns an appropriate reference code\n /// @param from Sending address\n /// @param to Receiving address\n /// @param value Amount of tokens being transferred\n /// @return Code by which to reference message for rejection reasoning\n /// @dev Overwrite with your custom transfer restriction logic\n function detectTransferRestriction(address from, address to, uint256 value) external view returns (uint8);\n\n /// @notice Returns a human-readable message for a given restriction code\n /// @param restrictionCode Identifier for looking up a message\n /// @return Text showing the restriction's reasoning\n /// @dev Overwrite with your custom message and restrictionCode handling\n function messageForTransferRestriction(uint8 restrictionCode) external view returns (string memory);\n}\n\ninterface IShareToken is IERC20Metadata, IERC7575Share, IERC1404 {\n // --- Events ---\n event File(bytes32 indexed what, address data);\n event SetHookData(address indexed user, bytes16 data);\n\n // --- Errors ---\n error NotAuthorizedOrHook();\n error ExceedsMaxSupply();\n error RestrictionsFailed();\n\n struct Balance {\n /// @dev The user balance is limited to uint128. This is safe because the decimals are limited to 18,\n /// thus the max balance is 2^128-1 / 10**18 = 3.40 * 10**20. This is also enforced on mint.\n uint128 amount;\n /// @dev There are 16 bytes that are used to store hook data (e.g. restrictions for users).\n bytes16 hookData;\n }\n\n // --- Administration ---\n /// @notice returns the hook that transfers perform callbacks to\n /// @dev MUST comply to `IHook` interface\n function hook() external view returns (address);\n\n /// @notice Updates a contract parameter\n /// @param what Accepts a bytes32 representation of 'name', 'symbol'\n function file(bytes32 what, string memory data) external;\n\n /// @notice Updates a contract parameter\n /// @param what Accepts a bytes32 representation of 'hook'\n function file(bytes32 what, address data) external;\n\n /// @notice updates the vault for a given `asset`\n function updateVault(address asset, address vault_) external;\n\n // --- ERC20 overrides ---\n /// @notice returns the 16 byte hook data of the given `user`.\n /// @dev Stored in the 128 most significant bits of the user balance\n function hookDataOf(address user) external view returns (bytes16);\n\n /// @notice update the 16 byte hook data of the given `user`\n function setHookData(address user, bytes16 hookData) external;\n\n /// @notice Function to mint tokens\n function mint(address user, uint256 value) external;\n\n /// @notice Function to burn tokens\n function burn(address user, uint256 value) external;\n\n /// @notice Checks if the tokens can be transferred given the input values\n function checkTransferRestriction(address from, address to, uint256 value) external view returns (bool);\n\n /// @notice Performs an authorized transfer, with `sender` as the given sender.\n /// @dev Requires allowance if `sender` != `from`\n function authTransferFrom(address sender, address from, address to, uint256 amount) external returns (bool);\n}\n" + }, + "src/vaults/legacy/LegacyVaultAdapter.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nimport {ILegacyVault} from \"src/vaults/legacy/interfaces/ILegacyVault.sol\";\nimport {IInvestmentManager} from \"src/vaults/legacy/interfaces/IInvestmentManager.sol\";\nimport {ILegacyVaultAdapter} from \"src/vaults/legacy/interfaces/ILegacyVaultAdapter.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\nimport {AsyncVault} from \"src/vaults/AsyncVault.sol\";\nimport {IAsyncRequestManager} from \"src/vaults/interfaces/investments/IAsyncRequestManager.sol\";\nimport {BaseAsyncRedeemVault, IAsyncRedeemVault} from \"src/vaults/BaseVaults.sol\";\n\n/// @title LegacyVaultAdapter\n/// @notice An adapter connecting legacy ERC-7540 vaults from Centrifuge V2 to Centrifuge V3.\n///\n/// @dev This adapter acts as an `IInvestmentManager` for a single legacy `ILegacyVault` vault from Centrifuge V2.\n/// At the same time it acts like a new `IAsyncVault` for the `IAsyncRequestManager` manager of Centrifuge V3.\n/// The adapter needs to be deployed per legacy vault and allows a seamless interaction between Centrifuge V2\n/// vaults and Centrifuge V3 infrastructure. Thereby, allowing to migrate existing vaults to the new system.\ncontract LegacyVaultAdapter is AsyncVault, ILegacyVaultAdapter, IInvestmentManager {\n uint64 public immutable legacyPoolId;\n bytes16 public immutable legacyTrancheId;\n ILegacyVault public immutable legacyVault;\n\n constructor(\n ILegacyVault legacyVault_,\n PoolId poolId,\n uint64 legacyPoolId_,\n ShareClassId scId,\n bytes16 legacyTrancheId_,\n address asset,\n IShareToken token,\n address root,\n IAsyncRequestManager manager\n ) AsyncVault(poolId, scId, asset, token, root, manager) {\n require(legacyVault_.poolId() == legacyPoolId_, NotLegacyPoolId(legacyPoolId_, legacyVault_.poolId()));\n require(\n legacyVault_.trancheId() == legacyTrancheId_, NotLegacyTrancheId(legacyTrancheId_, legacyVault_.trancheId())\n );\n require(legacyVault_.asset() == asset, NotLegacyAsset(asset, legacyVault_.asset()));\n require(legacyVault_.share() == address(token), NotLegacyShare(address(token), legacyVault_.share()));\n\n legacyPoolId = legacyPoolId_;\n legacyTrancheId = legacyTrancheId_;\n legacyVault = legacyVault_;\n }\n\n /// @dev Check if the msg.sender is the legacy vault\n modifier legacy() {\n require(msg.sender == address(legacyVault), NotLegacyVault(msg.sender, address(legacyVault)));\n _;\n }\n\n //----------------------------------------------------------------------------------------------\n // IInvestmentManager handlers\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IInvestmentManager\n function requestDeposit(address, /* vault */ uint256 assets, address receiver, address owner, address source)\n public\n legacy\n returns (bool)\n {\n return asyncManager().requestDeposit(this, assets, receiver, owner, source);\n }\n\n /// @inheritdoc IInvestmentManager\n function requestRedeem(address, /* vault */ uint256 shares, address receiver, address owner, address source)\n public\n legacy\n returns (bool)\n {\n return asyncManager().requestRedeem(this, shares, receiver, owner, source);\n }\n\n /// @inheritdoc IInvestmentManager\n function cancelDepositRequest(address, /* vault */ address owner, address source) public legacy {\n return asyncManager().cancelDepositRequest(this, owner, source);\n }\n\n /// @inheritdoc IInvestmentManager\n function cancelRedeemRequest(address, /* vault */ address owner, address source) public legacy {\n return asyncManager().cancelRedeemRequest(this, owner, source);\n }\n\n //----------------------------------------------------------------------------------------------\n // IInvestmentManager view methods\n //----------------------------------------------------------------------------------------------\n\n function escrow() public view returns (address) {\n return address(manager.globalEscrow());\n }\n\n /// @inheritdoc IInvestmentManager\n function convertToShares(address, /* vault */ uint256 _assets) public view returns (uint256 shares) {\n shares = asyncManager().convertToShares(this, _assets);\n }\n\n /// @inheritdoc IInvestmentManager\n function convertToAssets(address, /* vault */ uint256 _shares) public view returns (uint256 assets) {\n assets = asyncManager().convertToAssets(this, _shares);\n }\n\n /// @inheritdoc IInvestmentManager\n function maxDeposit(address, /* vault */ address user) public view returns (uint256 assets) {\n assets = asyncManager().maxDeposit(this, user);\n }\n\n /// @inheritdoc IInvestmentManager\n function maxMint(address, /* vault */ address user) public view returns (uint256 shares) {\n shares = asyncManager().maxMint(this, user);\n }\n\n /// @inheritdoc IInvestmentManager\n function maxWithdraw(address, /* vault */ address user) public view returns (uint256 assets) {\n assets = asyncManager().maxWithdraw(this, user);\n }\n\n /// @inheritdoc IInvestmentManager\n function maxRedeem(address, /* vault */ address user) public view returns (uint256 shares) {\n shares = asyncManager().maxRedeem(this, user);\n }\n\n /// @inheritdoc IInvestmentManager\n function pendingDepositRequest(address, /* vault */ address user) public view returns (uint256 assets) {\n assets = asyncManager().pendingDepositRequest(this, user);\n }\n\n /// @inheritdoc IInvestmentManager\n function pendingRedeemRequest(address, /* vault */ address user) public view returns (uint256 shares) {\n shares = asyncManager().pendingRedeemRequest(this, user);\n }\n\n /// @inheritdoc IInvestmentManager\n function pendingCancelDepositRequest(address, /* vault */ address user) public view returns (bool isPending) {\n isPending = asyncManager().pendingCancelDepositRequest(this, user);\n }\n\n /// @inheritdoc IInvestmentManager\n function pendingCancelRedeemRequest(address, /* vault */ address user) public view returns (bool isPending) {\n isPending = asyncManager().pendingCancelRedeemRequest(this, user);\n }\n\n /// @inheritdoc IInvestmentManager\n function claimableCancelDepositRequest(address, /* vault */ address user) public view returns (uint256 assets) {\n assets = asyncManager().claimableCancelDepositRequest(this, user);\n }\n\n /// @inheritdoc IInvestmentManager\n function claimableCancelRedeemRequest(address, /* vault */ address user) public view returns (uint256 shares) {\n shares = asyncManager().claimableCancelRedeemRequest(this, user);\n }\n\n /// @inheritdoc IInvestmentManager\n function priceLastUpdated(address /* vault */ ) public view returns (uint64 lastUpdated) {\n lastUpdated = manager.priceLastUpdated(this);\n }\n\n //----------------------------------------------------------------------------------------------\n // IInvestmentManager vault claim methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IInvestmentManager\n function deposit(address, /* vault */ uint256 assets, address receiver, address owner)\n public\n legacy\n returns (uint256 shares)\n {\n shares = asyncManager().deposit(this, assets, receiver, owner);\n }\n\n /// @inheritdoc IInvestmentManager\n function mint(address, /* vault */ uint256 shares, address receiver, address owner)\n public\n legacy\n returns (uint256 assets)\n {\n assets = asyncManager().mint(this, shares, receiver, owner);\n }\n\n /// @inheritdoc IInvestmentManager\n function redeem(address, /* vault */ uint256 shares, address receiver, address owner)\n public\n legacy\n returns (uint256 assets)\n {\n assets = asyncManager().redeem(this, shares, receiver, owner);\n }\n\n /// @inheritdoc IInvestmentManager\n function withdraw(address, /* vault */ uint256 assets, address receiver, address owner)\n public\n legacy\n returns (uint256 shares)\n {\n shares = asyncManager().withdraw(this, assets, receiver, owner);\n }\n\n /// @inheritdoc IInvestmentManager\n function claimCancelDepositRequest(address, /* vault */ address receiver, address owner)\n public\n legacy\n returns (uint256 assets)\n {\n assets = asyncManager().claimCancelDepositRequest(this, receiver, owner);\n }\n\n /// @inheritdoc IInvestmentManager\n function claimCancelRedeemRequest(address, /* vault */ address receiver, address owner)\n public\n legacy\n returns (uint256 shares)\n {\n shares = asyncManager().claimCancelRedeemRequest(this, receiver, owner);\n }\n\n //----------------------------------------------------------------------------------------------\n // Event emitters\n //----------------------------------------------------------------------------------------------\n\n function onDepositClaimable(address controller, uint256 assets, uint256 shares) public override auth {\n legacyVault.onDepositClaimable(controller, assets, shares);\n }\n\n function onCancelDepositClaimable(address controller, uint256 assets) public override auth {\n legacyVault.onCancelDepositClaimable(controller, assets);\n }\n\n function onRedeemRequest(address controller, address owner, uint256 shares)\n public\n override(BaseAsyncRedeemVault, IAsyncRedeemVault)\n auth\n {\n legacyVault.onRedeemRequest(controller, owner, shares);\n }\n\n function onRedeemClaimable(address controller, uint256 assets, uint256 shares)\n public\n override(BaseAsyncRedeemVault, IAsyncRedeemVault)\n auth\n {\n legacyVault.onRedeemClaimable(controller, assets, shares);\n }\n\n function onCancelRedeemClaimable(address controller, uint256 shares)\n public\n override(BaseAsyncRedeemVault, IAsyncRedeemVault)\n auth\n {\n legacyVault.onCancelRedeemClaimable(controller, shares);\n }\n}\n" + }, + "src/vaults/legacy/interfaces/IInvestmentManager.sol": { + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.5.0;\n\n/// @notice A stripped down version of the Centrifuge V2 investment manager.\n///\n/// @dev This interface is needed to ensure adapters for legacy vaults are provided with the expected interface.\ninterface IInvestmentManager {\n /// @notice Documentation see Centrifuge V2 repository.\n function escrow() external view returns (address);\n\n // --- Outgoing message handling ---\n /// @notice Documentation see Centrifuge V2 repository.\n function requestDeposit(address vault, uint256 assets, address receiver, address owner, address source)\n external\n returns (bool);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function requestRedeem(address vault, uint256 shares, address receiver, address, /* owner */ address source)\n external\n returns (bool);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function cancelDepositRequest(address vault, address owner, address source) external;\n\n /// @notice Documentation see Centrifuge V2 repository.\n function cancelRedeemRequest(address vault, address owner, address source) external;\n\n // --- View functions ---\n /// @notice Documentation see Centrifuge V2 repository.\n function convertToShares(address vault, uint256 _assets) external view returns (uint256 shares);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function convertToAssets(address vault, uint256 _shares) external view returns (uint256 assets);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function maxDeposit(address vault, address user) external view returns (uint256);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function maxMint(address vault, address user) external view returns (uint256 shares);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function maxWithdraw(address vault, address user) external view returns (uint256 assets);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function maxRedeem(address vault, address user) external view returns (uint256 shares);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function pendingDepositRequest(address vault, address user) external view returns (uint256 assets);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function pendingRedeemRequest(address vault, address user) external view returns (uint256 shares);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function pendingCancelDepositRequest(address vault, address user) external view returns (bool isPending);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function pendingCancelRedeemRequest(address vault, address user) external view returns (bool isPending);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function claimableCancelDepositRequest(address vault, address user) external view returns (uint256 assets);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function claimableCancelRedeemRequest(address vault, address user) external view returns (uint256 shares);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function priceLastUpdated(address vault) external view returns (uint64 lastUpdated);\n\n // --- Vault claim functions ---\n /// @notice Documentation see Centrifuge V2 repository.\n function deposit(address vault, uint256 assets, address receiver, address owner)\n external\n returns (uint256 shares);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function mint(address vault, uint256 shares, address receiver, address owner) external returns (uint256 assets);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function redeem(address vault, uint256 shares, address receiver, address owner) external returns (uint256 assets);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function withdraw(address vault, uint256 assets, address receiver, address owner)\n external\n returns (uint256 shares);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function claimCancelDepositRequest(address vault, address receiver, address owner)\n external\n returns (uint256 assets);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function claimCancelRedeemRequest(address vault, address receiver, address owner)\n external\n returns (uint256 shares);\n}\n" + }, + "src/vaults/legacy/interfaces/ILegacyVault.sol": { + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.5.0;\n\n/// @notice A stripped down version of the Centrifuge V2 ERC-7540 vault.\n///\n/// @dev This interface is needed to ensure adapters for legacy vaults are provided with the expected interface.\ninterface ILegacyVault {\n /// @notice Documentation see Centrifuge V2 repository.\n function poolId() external view returns (uint64);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function trancheId() external view returns (bytes16);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function asset() external view returns (address);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function share() external view returns (address);\n\n /// @notice Callback when a redeem Request is triggered externally;\n function onRedeemRequest(address controller, address owner, uint256 shares) external;\n\n /// @notice Callback when a deposit Request becomes claimable\n function onDepositClaimable(address owner, uint256 assets, uint256 shares) external;\n\n /// @notice Callback when a redeem Request becomes claimable\n function onRedeemClaimable(address owner, uint256 assets, uint256 shares) external;\n\n /// @notice Callback when a claim deposit Request becomes claimable\n function onCancelDepositClaimable(address owner, uint256 assets) external;\n\n /// @notice Callback when a claim redeem Request becomes claimable\n function onCancelRedeemClaimable(address owner, uint256 shares) external;\n}\n" + }, + "src/vaults/legacy/interfaces/ILegacyVaultAdapter.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\ninterface ILegacyVaultAdapter {\n error NotLegacyVault(address sender, address legacyVault);\n error NotLegacyPoolId(uint64 providedPoolId, uint64 legacyPoolId);\n error NotLegacyTrancheId(bytes16 providedTrancheId, bytes16 legacyTrancheId);\n error NotLegacyAsset(address providedAsset, address legacyAsset);\n error NotLegacyShare(address providedShare, address legacyShare);\n}\n" + }, + "src/vaults/token/ShareToken.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {ERC20} from \"src/misc/ERC20.sol\";\nimport {IERC20, IERC20Metadata} from \"src/misc/interfaces/IERC20.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {IERC7575Share, IERC165} from \"src/misc/interfaces/IERC7575.sol\";\n\nimport {\n IHook,\n HookData,\n SUCCESS_CODE_ID,\n SUCCESS_MESSAGE,\n ERROR_CODE_ID,\n ERROR_MESSAGE\n} from \"src/common/interfaces/IHook.sol\";\nimport {IShareToken, IERC1404} from \"src/vaults/interfaces/token/IShareToken.sol\";\n\n/// @title Share Token\n/// @notice Extension of ERC20 + ERC1404,\n/// integrating an external hook optionally for ERC20 callbacks and ERC1404 checks.\ncontract ShareToken is ERC20, IShareToken {\n using MathLib for uint256;\n\n mapping(address => Balance) private balances;\n\n /// @inheritdoc IShareToken\n address public hook;\n\n /// @inheritdoc IERC7575Share\n mapping(address asset => address) public vault;\n\n constructor(uint8 decimals_) ERC20(decimals_) {}\n\n modifier authOrHook() {\n require(wards[msg.sender] == 1 || msg.sender == hook, NotAuthorizedOrHook());\n _;\n }\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IShareToken\n function file(bytes32 what, address data) external authOrHook {\n if (what == \"hook\") hook = data;\n else revert FileUnrecognizedParam();\n emit File(what, data);\n }\n\n /// @inheritdoc IShareToken\n function file(bytes32 what, string memory data) public override(ERC20, IShareToken) auth {\n super.file(what, data);\n }\n\n /// @inheritdoc IShareToken\n function updateVault(address asset, address vault_) external auth {\n vault[asset] = vault_;\n emit VaultUpdate(asset, vault_);\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-20 overrides\n //----------------------------------------------------------------------------------------------\n\n function _balanceOf(address user) internal view override returns (uint256) {\n return balances[user].amount;\n }\n\n function _setBalance(address user, uint256 value) internal override {\n balances[user].amount = value.toUint128();\n }\n\n /// @inheritdoc IShareToken\n function hookDataOf(address user) public view returns (bytes16) {\n return balances[user].hookData;\n }\n\n /// @inheritdoc IShareToken\n function setHookData(address user, bytes16 hookData) public authOrHook {\n balances[user].hookData = hookData;\n emit SetHookData(user, hookData);\n }\n\n /// @inheritdoc IERC20\n function transfer(address to, uint256 value) public override(ERC20, IERC20) returns (bool success) {\n success = super.transfer(to, value);\n _onTransfer(msg.sender, to, value);\n }\n\n /// @inheritdoc IERC20\n function transferFrom(address from, address to, uint256 value)\n public\n override(ERC20, IERC20)\n returns (bool success)\n {\n success = super.transferFrom(from, to, value);\n _onTransfer(from, to, value);\n }\n\n /// @inheritdoc IShareToken\n function mint(address to, uint256 value) public override(ERC20, IShareToken) {\n super.mint(to, value);\n require(totalSupply <= type(uint128).max, ExceedsMaxSupply());\n _onTransfer(address(0), to, value);\n }\n\n /// @inheritdoc IShareToken\n function burn(address from, uint256 value) public override(ERC20, IShareToken) {\n super.burn(from, value);\n _onTransfer(from, address(0), value);\n }\n\n function _onTransfer(address from, address to, uint256 value) internal {\n address hook_ = hook;\n require(\n hook_ == address(0)\n || IHook(hook_).onERC20Transfer(from, to, value, HookData(hookDataOf(from), hookDataOf(to)))\n == IHook.onERC20Transfer.selector,\n RestrictionsFailed()\n );\n }\n\n /// @inheritdoc IShareToken\n function authTransferFrom(address sender, address from, address to, uint256 value)\n public\n auth\n returns (bool success)\n {\n success = _transferFrom(sender, from, to, value);\n address hook_ = hook;\n if (hook_ != address(0)) {\n IHook(hook_).onERC20AuthTransfer(sender, from, to, value, HookData(hookDataOf(from), hookDataOf(to)));\n }\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-1404\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IShareToken\n function checkTransferRestriction(address from, address to, uint256 value) public view returns (bool) {\n return detectTransferRestriction(from, to, value) == SUCCESS_CODE_ID;\n }\n\n /// @inheritdoc IERC1404\n function detectTransferRestriction(address from, address to, uint256 value) public view returns (uint8) {\n address hook_ = hook;\n if (hook_ == address(0)) return SUCCESS_CODE_ID;\n return IHook(hook_).checkERC20Transfer(from, to, value, HookData(hookDataOf(from), hookDataOf(to)))\n ? SUCCESS_CODE_ID\n : ERROR_CODE_ID;\n }\n\n /// @inheritdoc IERC1404\n function messageForTransferRestriction(uint8 restrictionCode) external pure returns (string memory) {\n return restrictionCode == SUCCESS_CODE_ID ? SUCCESS_MESSAGE : ERROR_MESSAGE;\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-165\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC165\n function supportsInterface(bytes4 interfaceId) external pure override returns (bool) {\n return interfaceId == type(IERC7575Share).interfaceId || interfaceId == type(IERC165).interfaceId;\n }\n}\n" + } + }, + "settings": { + "remappings": [ + "forge-std/=lib/forge-std/src/", + "@chimera/=lib/chimera/src/", + "chimera/=lib/chimera/src/", + "ds-test/=lib/chimera/lib/forge-std/lib/ds-test/src/" + ], + "optimizer": { "enabled": true, "runs": 1 }, + "metadata": { + "useLiteralContent": false, + "bytecodeHash": "none", + "appendCBOR": true + }, + "outputSelection": { + "*": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + } + }, + "evmVersion": "cancun", + "viaIR": true, + "libraries": {} + } +} diff --git a/crates/resolc/src/tests/data/standard_json/pvm_codegen_one_file.json b/crates/resolc/src/tests/data/standard_json/pvm_codegen_one_file.json new file mode 100644 index 0000000..5488e4a --- /dev/null +++ b/crates/resolc/src/tests/data/standard_json/pvm_codegen_one_file.json @@ -0,0 +1,720 @@ +{ + "language": "Solidity", + "sources": { + "lib/forge-std/src/interfaces/IERC165.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.6.2;\n\ninterface IERC165 {\n /// @notice Query if a contract implements an interface\n /// @param interfaceID The interface identifier, as specified in ERC-165\n /// @dev Interface identification is specified in ERC-165. This function\n /// uses less than 30,000 gas.\n /// @return `true` if the contract implements `interfaceID` and\n /// `interfaceID` is not 0xffffffff, `false` otherwise\n function supportsInterface(bytes4 interfaceID) external view returns (bool);\n}\n" + }, + "src/common/GasService.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IGasService} from \"src/common/interfaces/IGasService.sol\";\n\n/// @title GasService\n/// @notice This is a utility contract used to determine the execution gas limit\n/// for a payload being sent across all supported adapters.\ncontract GasService is IGasService {\n uint128 internal immutable _maxBatchSize;\n uint128 internal immutable _messageGasLimit;\n\n constructor(uint128 maxBatchSize_, uint128 messageGasLimit) {\n _maxBatchSize = maxBatchSize_;\n _messageGasLimit = messageGasLimit;\n }\n\n /// @inheritdoc IGasService\n function maxBatchSize(uint16) public view returns (uint128) {\n return _maxBatchSize;\n }\n\n /// @inheritdoc IGasService\n function gasLimit(uint16, bytes calldata) public view returns (uint128) {\n return _messageGasLimit;\n }\n}\n" + }, + "src/common/Gateway.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {ArrayLib} from \"src/misc/libraries/ArrayLib.sol\";\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {Recoverable, IRecoverable, ETH_ADDRESS} from \"src/misc/Recoverable.sol\";\nimport {TransientArrayLib} from \"src/misc/libraries/TransientArrayLib.sol\";\nimport {TransientBytesLib} from \"src/misc/libraries/TransientBytesLib.sol\";\nimport {TransientStorageLib} from \"src/misc/libraries/TransientStorageLib.sol\";\n\nimport {IRoot} from \"src/common/interfaces/IRoot.sol\";\nimport {IGasService} from \"src/common/interfaces/IGasService.sol\";\nimport {IAdapter} from \"src/common/interfaces/IAdapter.sol\";\nimport {IMessageProcessor} from \"src/common/interfaces/IMessageProcessor.sol\";\nimport {IMessageSender} from \"src/common/interfaces/IMessageSender.sol\";\nimport {IGateway} from \"src/common/interfaces/IGateway.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {IGatewayHandler} from \"src/common/interfaces/IGatewayHandlers.sol\";\nimport {MessageProofLib} from \"src/common/libraries/MessageProofLib.sol\";\n\n/// @title Gateway\n/// @notice Routing contract that forwards outgoing messages to multiple adapters (1 full message, n-1 proofs)\n/// and validates that multiple adapters have confirmed a message.\n///\n/// Supports batching multiple messages, as well as paying for methods manually or through pool-level subsidies.\n///\n/// Supports processing multiple duplicate messages in parallel by storing counts of messages\n/// and proofs that have been received. Also implements a retry method for failed messages.\ncontract Gateway is Auth, Recoverable, IGateway {\n using BytesLib for bytes;\n using MathLib for uint256;\n using MessageProofLib for *;\n using ArrayLib for uint16[8];\n using TransientStorageLib for bytes32;\n\n uint8 public constant MAX_ADAPTER_COUNT = 8;\n uint8 public constant PRIMARY_ADAPTER_ID = 1;\n PoolId public constant GLOBAL_POT = PoolId.wrap(0);\n uint256 public constant RECOVERY_CHALLENGE_PERIOD = 7 days;\n bytes32 public constant BATCH_LOCATORS_SLOT = bytes32(uint256(keccak256(\"Centrifuge/batch-locators\")) - 1);\n\n uint16 public immutable localCentrifugeId;\n\n // Dependencies\n IRoot public immutable root;\n IGasService public gasService;\n IMessageProcessor public processor;\n\n // Outbound & payments\n bool public transient isBatching;\n uint256 public transient fuel;\n address public transient transactionRefund;\n mapping(PoolId => Funds) public subsidy;\n mapping(uint16 centrifugeId => mapping(bytes32 batchHash => Underpaid)) public underpaid;\n\n // Adapters\n mapping(uint16 centrifugeId => IAdapter[]) public adapters;\n mapping(uint16 centrifugeId => mapping(IAdapter adapter => Adapter)) internal _activeAdapters;\n\n // Inbound & recoveries\n mapping(uint16 centrifugeId => mapping(bytes32 messageHash => uint256)) public failedMessages;\n mapping(uint16 centrifugeId => mapping(bytes32 batchHash => InboundBatch)) public inboundBatch;\n mapping(uint16 centrifugeId => mapping(IAdapter adapter => mapping(bytes32 payloadHash => uint256 timestamp)))\n public recoveries;\n\n constructor(uint16 localCentrifugeId_, IRoot root_, IGasService gasService_, address deployer) Auth(deployer) {\n localCentrifugeId = localCentrifugeId_;\n root = root_;\n gasService = gasService_;\n\n setRefundAddress(GLOBAL_POT, IRecoverable(address(this)));\n }\n\n modifier pauseable() {\n require(!root.paused(), Paused());\n _;\n }\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IGateway\n function file(bytes32 what, uint16 centrifugeId, IAdapter[] calldata addresses) external auth {\n if (what == \"adapters\") {\n uint8 quorum_ = addresses.length.toUint8();\n require(quorum_ != 0, EmptyAdapterSet());\n require(quorum_ <= MAX_ADAPTER_COUNT, ExceedsMax());\n\n // Increment session id to reset pending votes\n uint256 numAdapters = adapters[centrifugeId].length;\n uint64 sessionId =\n numAdapters > 0 ? _activeAdapters[centrifugeId][adapters[centrifugeId][0]].activeSessionId + 1 : 0;\n\n // Disable old adapters\n for (uint8 i; i < numAdapters; i++) {\n delete _activeAdapters[centrifugeId][adapters[centrifugeId][i]];\n }\n\n // Enable new adapters, setting quorum to number of adapters\n for (uint8 j; j < quorum_; j++) {\n require(_activeAdapters[centrifugeId][addresses[j]].id == 0, NoDuplicatesAllowed());\n\n // Ids are assigned sequentially starting at 1\n _activeAdapters[centrifugeId][addresses[j]] = Adapter(j + 1, quorum_, sessionId);\n }\n\n adapters[centrifugeId] = addresses;\n } else {\n revert FileUnrecognizedParam();\n }\n\n emit File(what, centrifugeId, addresses);\n }\n\n /// @inheritdoc IGateway\n function file(bytes32 what, address instance) external auth {\n if (what == \"gasService\") gasService = IGasService(instance);\n else if (what == \"processor\") processor = IMessageProcessor(instance);\n else revert FileUnrecognizedParam();\n\n emit File(what, instance);\n }\n\n receive() external payable {\n _subsidizePool(GLOBAL_POT, msg.sender, msg.value);\n }\n\n //----------------------------------------------------------------------------------------------\n // Incoming\n //----------------------------------------------------------------------------------------------\n\n /// @dev Handle an inbound payload\n function handle(uint16 centrifugeId, bytes calldata payload) external pauseable {\n _handle(centrifugeId, payload, IAdapter(msg.sender), false);\n }\n\n function _handle(uint16 centrifugeId, bytes calldata payload, IAdapter adapter_, bool isRecovery) internal {\n Adapter memory adapter = _activeAdapters[centrifugeId][adapter_];\n require(adapter.id != 0, InvalidAdapter());\n\n IMessageProcessor processor_ = processor;\n if (processor_.isMessageRecovery(payload)) {\n require(!isRecovery, RecoveryPayloadRecovered());\n return processor_.handle(centrifugeId, payload);\n }\n\n bool isMessageProof = payload.toUint8(0) == MessageProofLib.MESSAGE_PROOF_ID;\n\n // Verify adapter and parse message hash\n bytes32 batchHash;\n if (isMessageProof) {\n require(adapter.id != PRIMARY_ADAPTER_ID, NonProofAdapter());\n\n batchHash = payload.deserializeMessageProof();\n bytes32 payloadId = keccak256(abi.encodePacked(centrifugeId, localCentrifugeId, batchHash));\n emit HandleProof(centrifugeId, payloadId, batchHash, adapter_);\n } else {\n require(adapter.id == PRIMARY_ADAPTER_ID, NonBatchAdapter());\n\n batchHash = keccak256(payload);\n bytes32 payloadId = keccak256(abi.encodePacked(centrifugeId, localCentrifugeId, batchHash));\n emit HandleBatch(centrifugeId, payloadId, payload, adapter_);\n }\n\n // Special case for gas efficiency\n if (adapter.quorum == 1 && !isMessageProof) {\n _handleBatch(centrifugeId, payload);\n return;\n }\n\n InboundBatch storage state = inboundBatch[centrifugeId][batchHash];\n\n if (adapter.activeSessionId != state.sessionId) {\n // Clear votes from previous session\n delete state.votes;\n state.sessionId = adapter.activeSessionId;\n }\n\n // Increase vote\n state.votes[adapter.id - 1]++;\n\n if (state.votes.countNonZeroValues() >= adapter.quorum) {\n // Reduce votes by quorum\n state.votes.decreaseFirstNValues(adapter.quorum);\n\n if (isMessageProof) {\n _handleBatch(centrifugeId, state.pendingBatch);\n } else {\n _handleBatch(centrifugeId, payload);\n }\n\n // Only if there are no more pending messages, remove the pending message\n if (state.votes.isEmpty()) {\n delete state.pendingBatch;\n }\n } else if (!isMessageProof) {\n state.pendingBatch = payload;\n }\n }\n\n function _handleBatch(uint16 centrifugeId, bytes memory batch_) internal {\n IMessageProcessor processor_ = processor;\n bytes memory remaining = batch_;\n\n while (remaining.length > 0) {\n uint256 length = processor_.messageLength(remaining);\n bytes memory message = remaining.slice(0, length);\n remaining = remaining.slice(length, remaining.length - length);\n\n try processor_.handle(centrifugeId, message) {\n emit ExecuteMessage(centrifugeId, message);\n } catch (bytes memory err) {\n bytes32 messageHash = keccak256(message);\n failedMessages[centrifugeId][messageHash]++;\n emit FailMessage(centrifugeId, message, err);\n }\n }\n }\n\n /// @inheritdoc IGateway\n function retry(uint16 centrifugeId, bytes memory message) external pauseable {\n bytes32 messageHash = keccak256(message);\n require(failedMessages[centrifugeId][messageHash] > 0, NotFailedMessage());\n\n processor.handle(centrifugeId, message);\n failedMessages[centrifugeId][messageHash]--;\n\n emit ExecuteMessage(centrifugeId, message);\n }\n\n /// @inheritdoc IGatewayHandler\n function initiateRecovery(uint16 centrifugeId, IAdapter adapter, bytes32 payloadHash) external auth {\n require(_activeAdapters[centrifugeId][adapter].id != 0, InvalidAdapter());\n recoveries[centrifugeId][adapter][payloadHash] = block.timestamp + RECOVERY_CHALLENGE_PERIOD;\n emit InitiateRecovery(centrifugeId, payloadHash, adapter);\n }\n\n /// @inheritdoc IGatewayHandler\n function disputeRecovery(uint16 centrifugeId, IAdapter adapter, bytes32 payloadHash) external auth {\n delete recoveries[centrifugeId][adapter][payloadHash];\n emit DisputeRecovery(centrifugeId, payloadHash, adapter);\n }\n\n /// @inheritdoc IGateway\n function executeRecovery(uint16 centrifugeId, IAdapter adapter, bytes calldata payload) external {\n bytes32 payloadHash = keccak256(payload);\n uint256 recovery = recoveries[centrifugeId][adapter][payloadHash];\n\n require(recovery != 0, RecoveryNotInitiated());\n require(recovery <= block.timestamp, RecoveryChallengePeriodNotEnded());\n\n delete recoveries[centrifugeId][adapter][payloadHash];\n _handle(centrifugeId, payload, adapter, true);\n emit ExecuteRecovery(centrifugeId, payload, adapter);\n }\n\n //----------------------------------------------------------------------------------------------\n // Outgoing\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IMessageSender\n function send(uint16 centrifugeId, bytes calldata message) external pauseable auth {\n require(message.length > 0, EmptyMessage());\n\n PoolId poolId = processor.messagePoolId(message);\n\n emit PrepareMessage(centrifugeId, poolId, message);\n\n if (isBatching) {\n bytes32 batchSlot = _outboundBatchSlot(centrifugeId, poolId);\n bytes memory previousMessage = TransientBytesLib.get(batchSlot);\n\n bytes32 gasLimitSlot = _gasLimitSlot(centrifugeId, poolId);\n uint128 newGasLimit = gasLimitSlot.tloadUint128() + gasService.gasLimit(centrifugeId, message);\n require(newGasLimit <= gasService.maxBatchSize(centrifugeId), ExceedsMaxBatchSize());\n gasLimitSlot.tstore(uint256(newGasLimit));\n\n if (previousMessage.length == 0) {\n TransientArrayLib.push(BATCH_LOCATORS_SLOT, _encodeLocator(centrifugeId, poolId));\n }\n\n TransientBytesLib.append(batchSlot, message);\n } else {\n _send(centrifugeId, poolId, message, gasService.gasLimit(centrifugeId, message));\n _refundTransaction();\n }\n }\n\n function _send(uint16 centrifugeId, PoolId poolId, bytes memory batch, uint128 batchGasLimit)\n internal\n returns (bool succeeded)\n {\n IAdapter[] memory adapters_ = adapters[centrifugeId];\n require(adapters[centrifugeId].length != 0, EmptyAdapterSet());\n\n SendData memory data = SendData({\n batchHash: keccak256(batch),\n payloadId: bytes32(\"\"),\n gasCost: new uint256[](MAX_ADAPTER_COUNT)\n });\n data.payloadId = keccak256(abi.encodePacked(localCentrifugeId, centrifugeId, data.batchHash));\n\n {\n // Estimate gas usage\n uint256 total;\n for (uint256 i; i < adapters_.length; i++) {\n data.gasCost[i] = adapters_[i].estimate(\n centrifugeId,\n i == PRIMARY_ADAPTER_ID - 1 ? batch : data.batchHash.serializeMessageProof(),\n batchGasLimit\n );\n\n total += data.gasCost[i];\n }\n\n // Ensure sufficient funds are available\n if (transactionRefund != address(0)) {\n require(total <= fuel, NotEnoughTransactionGas());\n fuel -= total;\n } else {\n if (total > subsidy[poolId].value) {\n _requestPoolFunding(poolId);\n }\n\n if (total <= subsidy[poolId].value) {\n subsidy[poolId].value -= uint96(total);\n } else {\n underpaid[centrifugeId][data.batchHash].counter++;\n underpaid[centrifugeId][data.batchHash].gasLimit = batchGasLimit;\n emit UnderpaidBatch(centrifugeId, batch);\n return false;\n }\n }\n }\n\n // Send batch and proofs\n for (uint256 j; j < adapters_.length; j++) {\n bytes32 adapterData = adapters_[j].send{value: data.gasCost[j]}(\n centrifugeId,\n j == PRIMARY_ADAPTER_ID - 1 ? batch : data.batchHash.serializeMessageProof(),\n batchGasLimit,\n transactionRefund != address(0) ? transactionRefund : address(subsidy[poolId].refund)\n );\n\n if (j == PRIMARY_ADAPTER_ID - 1) {\n emit SendBatch(\n centrifugeId,\n data.payloadId,\n batch,\n adapters_[j],\n adapterData,\n transactionRefund != address(0) ? transactionRefund : address(subsidy[poolId].refund)\n );\n } else {\n emit SendProof(\n centrifugeId,\n data.payloadId,\n data.batchHash,\n adapters_[j],\n adapterData\n );\n }\n }\n\n return true;\n }\n\n /// @inheritdoc IGateway\n function repay(uint16 centrifugeId, bytes memory batch) external payable pauseable {\n bytes32 batchHash = keccak256(batch);\n Underpaid storage underpaid_ = underpaid[centrifugeId][batchHash];\n require(underpaid_.counter > 0, NotUnderpaidBatch());\n\n PoolId poolId = processor.messagePoolId(batch);\n if (msg.value > 0) subsidizePool(poolId);\n\n require(_send(centrifugeId, poolId, batch, underpaid_.gasLimit), InsufficientFundsForRepayment());\n underpaid[centrifugeId][batchHash].counter--;\n\n emit RepayBatch(centrifugeId, batch);\n }\n\n function _refundTransaction() internal {\n if (transactionRefund == address(0)) return;\n\n // Reset before external call\n uint256 fuel_ = fuel;\n address transactionRefund_ = transactionRefund;\n fuel = 0;\n transactionRefund = address(0);\n\n if (fuel_ > 0) {\n (bool success,) = payable(transactionRefund_).call{value: fuel_}(new bytes(0));\n\n if (!success) {\n // If refund fails, move remaining fuel to global pot\n _subsidizePool(GLOBAL_POT, transactionRefund_, fuel_);\n }\n }\n }\n\n function _requestPoolFunding(PoolId poolId) internal {\n IRecoverable refund = subsidy[poolId].refund;\n if (!poolId.isNull() && address(refund) != address(0)) {\n uint256 refundBalance = address(refund).balance;\n if (refundBalance == 0) return;\n\n // Send to the gateway GLOBAL_POT\n refund.recoverTokens(ETH_ADDRESS, address(this), refundBalance);\n\n // Extract from the GLOBAL_POT\n subsidy[GLOBAL_POT].value -= uint96(refundBalance);\n _subsidizePool(poolId, address(refund), refundBalance);\n }\n }\n\n /// @inheritdoc IGateway\n function setRefundAddress(PoolId poolId, IRecoverable refund) public auth {\n subsidy[poolId].refund = refund;\n emit SetRefundAddress(poolId, refund);\n }\n\n /// @inheritdoc IGateway\n function subsidizePool(PoolId poolId) public payable {\n require(address(subsidy[poolId].refund) != address(0), RefundAddressNotSet());\n _subsidizePool(poolId, msg.sender, msg.value);\n }\n\n function _subsidizePool(PoolId poolId, address who, uint256 value) internal {\n subsidy[poolId].value += uint96(value);\n emit SubsidizePool(poolId, who, value);\n }\n\n /// @inheritdoc IGateway\n function payTransaction(address payer) external payable auth {\n transactionRefund = payer;\n fuel += msg.value;\n }\n\n /// @inheritdoc IGateway\n function startBatching() external auth {\n isBatching = true;\n }\n\n /// @inheritdoc IGateway\n function endBatching() external auth {\n require(isBatching, NoBatched());\n\n bytes32[] memory locators = TransientArrayLib.getBytes32(BATCH_LOCATORS_SLOT);\n for (uint256 i; i < locators.length; i++) {\n (uint16 centrifugeId, PoolId poolId) = _parseLocator(locators[i]);\n bytes32 outboundBatchSlot = _outboundBatchSlot(centrifugeId, poolId);\n uint128 gasLimit = _gasLimitSlot(centrifugeId, poolId).tloadUint128();\n\n _send(centrifugeId, poolId, TransientBytesLib.get(outboundBatchSlot), gasLimit);\n\n TransientBytesLib.clear(outboundBatchSlot);\n _gasLimitSlot(centrifugeId, poolId).tstore(uint256(0));\n }\n\n TransientArrayLib.clear(BATCH_LOCATORS_SLOT);\n isBatching = false;\n\n _refundTransaction();\n }\n\n function _encodeLocator(uint16 centrifugeId, PoolId poolId) internal pure returns (bytes32) {\n return bytes32(abi.encodePacked(bytes2(centrifugeId), bytes8(poolId.raw())));\n }\n\n function _parseLocator(bytes32 locator) internal pure returns (uint16 centrifugeId, PoolId poolId) {\n centrifugeId = uint16(bytes2(locator));\n poolId = PoolId.wrap(uint64(bytes8(locator << 16)));\n }\n\n function _gasLimitSlot(uint16 centrifugeId, PoolId poolId) internal pure returns (bytes32) {\n return keccak256(abi.encode(\"batchGasLimit\", centrifugeId, poolId));\n }\n\n function _outboundBatchSlot(uint16 centrifugeId, PoolId poolId) internal pure returns (bytes32) {\n return keccak256(abi.encode(\"outboundBatch\", centrifugeId, poolId));\n }\n\n //----------------------------------------------------------------------------------------------\n // View methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IGateway\n function estimate(uint16 centrifugeId, bytes calldata payload) external view returns (uint256 total) {\n bytes memory proof = keccak256(payload).serializeMessageProof();\n\n uint256 gasLimit = 0;\n for (uint256 pos; pos < payload.length;) {\n bytes calldata inner = payload[pos:payload.length];\n gasLimit += gasService.gasLimit(centrifugeId, inner);\n pos += processor.messageLength(inner);\n }\n\n uint256 adaptersCount = adapters[centrifugeId].length;\n for (uint256 i; i < adaptersCount; i++) {\n bytes memory message = i == PRIMARY_ADAPTER_ID - 1 ? payload : proof;\n total += IAdapter(adapters[centrifugeId][i]).estimate(centrifugeId, message, gasLimit);\n }\n }\n\n /// @inheritdoc IGateway\n function quorum(uint16 centrifugeId) external view returns (uint8) {\n Adapter memory adapter = _activeAdapters[centrifugeId][adapters[centrifugeId][0]];\n return adapter.quorum;\n }\n\n /// @inheritdoc IGateway\n function activeSessionId(uint16 centrifugeId) external view returns (uint64) {\n Adapter memory adapter = _activeAdapters[centrifugeId][adapters[centrifugeId][0]];\n return adapter.activeSessionId;\n }\n\n /// @inheritdoc IGateway\n function votes(uint16 centrifugeId, bytes32 batchHash) external view returns (uint16[MAX_ADAPTER_COUNT] memory) {\n return inboundBatch[centrifugeId][batchHash].votes;\n }\n}\n\n" + }, + "src/common/Guardian.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {IRoot} from \"src/common/interfaces/IRoot.sol\";\nimport {IAdapter} from \"src/common/interfaces/IAdapter.sol\";\nimport {IGuardian, ISafe} from \"src/common/interfaces/IGuardian.sol\";\nimport {IRootMessageSender} from \"src/common/interfaces/IGatewaySenders.sol\";\nimport {IHubGuardianActions} from \"src/common/interfaces/IGuardianActions.sol\";\n\ncontract Guardian is IGuardian {\n using CastLib for address;\n\n IRoot public immutable root;\n\n IHubGuardianActions public hub;\n ISafe public safe;\n IRootMessageSender public sender;\n\n constructor(ISafe safe_, IRoot root_, IRootMessageSender messageDispatcher_) {\n root = root_;\n safe = safe_;\n sender = messageDispatcher_;\n }\n\n modifier onlySafe() {\n require(msg.sender == address(safe), NotTheAuthorizedSafe());\n _;\n }\n\n modifier onlySafeOrOwner() {\n require(msg.sender == address(safe) || _isSafeOwner(msg.sender), NotTheAuthorizedSafeOrItsOwner());\n _;\n }\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IGuardian\n function file(bytes32 what, address data) external onlySafe {\n if (what == \"safe\") safe = ISafe(data);\n else if (what == \"sender\") sender = IRootMessageSender(data);\n else if (what == \"hub\") hub = IHubGuardianActions(data);\n else revert FileUnrecognizedParam();\n\n emit File(what, data);\n }\n\n //----------------------------------------------------------------------------------------------\n // Admin actions\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IGuardian\n function createPool(PoolId poolId, address admin, AssetId currency) external onlySafe {\n return hub.createPool(poolId, admin, currency);\n }\n\n /// @inheritdoc IGuardian\n function pause() external onlySafeOrOwner {\n root.pause();\n }\n\n /// @inheritdoc IGuardian\n function unpause() external onlySafe {\n root.unpause();\n }\n\n /// @inheritdoc IGuardian\n function scheduleRely(address target) external onlySafe {\n root.scheduleRely(target);\n }\n\n /// @inheritdoc IGuardian\n function cancelRely(address target) external onlySafe {\n root.cancelRely(target);\n }\n\n /// @inheritdoc IGuardian\n function scheduleUpgrade(uint16 centrifugeId, address target) external onlySafe {\n sender.sendScheduleUpgrade(centrifugeId, target.toBytes32());\n }\n\n /// @inheritdoc IGuardian\n function cancelUpgrade(uint16 centrifugeId, address target) external onlySafe {\n sender.sendCancelUpgrade(centrifugeId, target.toBytes32());\n }\n\n /// @inheritdoc IGuardian\n function recoverTokens(\n uint16 centrifugeId,\n address target,\n address token,\n uint256 tokenId,\n address to,\n uint256 amount\n ) external onlySafe {\n sender.sendRecoverTokens(centrifugeId, target.toBytes32(), token.toBytes32(), tokenId, to.toBytes32(), amount);\n }\n\n /// @inheritdoc IGuardian\n function initiateRecovery(uint16 centrifugeId, uint16 adapterCentrifugeId, IAdapter adapter, bytes32 hash)\n external\n onlySafe\n {\n sender.sendInitiateRecovery(centrifugeId, adapterCentrifugeId, address(adapter).toBytes32(), hash);\n }\n\n /// @inheritdoc IGuardian\n function disputeRecovery(uint16 centrifugeId, uint16 adapterCentrifugeId, IAdapter adapter, bytes32 hash)\n external\n onlySafe\n {\n sender.sendDisputeRecovery(centrifugeId, adapterCentrifugeId, address(adapter).toBytes32(), hash);\n }\n\n //----------------------------------------------------------------------------------------------\n // Helpers\n //----------------------------------------------------------------------------------------------\n\n function _isSafeOwner(address addr) internal view returns (bool) {\n try safe.isOwner(addr) returns (bool isOwner) {\n return isOwner;\n } catch {\n return false;\n }\n }\n}\n" + }, + "src/common/MessageDispatcher.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {D18, d18} from \"src/misc/types/D18.sol\";\nimport {IRecoverable} from \"src/misc/interfaces/IRecoverable.sol\";\n\nimport {MessageLib} from \"src/common/libraries/MessageLib.sol\";\nimport {IAdapter} from \"src/common/interfaces/IAdapter.sol\";\nimport {IGateway} from \"src/common/interfaces/IGateway.sol\";\nimport {IRoot} from \"src/common/interfaces/IRoot.sol\";\nimport {\n IRequestManagerGatewayHandler,\n IPoolManagerGatewayHandler,\n IBalanceSheetGatewayHandler,\n IHubGatewayHandler\n} from \"src/common/interfaces/IGatewayHandlers.sol\";\nimport {IVaultMessageSender, IPoolMessageSender, IRootMessageSender} from \"src/common/interfaces/IGatewaySenders.sol\";\n\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {IMessageDispatcher} from \"src/common/interfaces/IMessageDispatcher.sol\";\nimport {ITokenRecoverer} from \"src/common/interfaces/ITokenRecoverer.sol\";\n\ncontract MessageDispatcher is Auth, IMessageDispatcher {\n using CastLib for *;\n using MessageLib for *;\n using BytesLib for bytes;\n using MathLib for uint256;\n\n IRoot public immutable root;\n IGateway public immutable gateway;\n ITokenRecoverer public immutable tokenRecoverer;\n\n uint16 public immutable localCentrifugeId;\n\n IHubGatewayHandler public hub;\n IPoolManagerGatewayHandler public poolManager;\n IRequestManagerGatewayHandler public investmentManager;\n IBalanceSheetGatewayHandler public balanceSheet;\n\n constructor(\n uint16 localCentrifugeId_,\n IRoot root_,\n IGateway gateway_,\n ITokenRecoverer tokenRecoverer_,\n address deployer\n ) Auth(deployer) {\n localCentrifugeId = localCentrifugeId_;\n root = root_;\n gateway = gateway_;\n tokenRecoverer = tokenRecoverer_;\n }\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IMessageDispatcher\n function file(bytes32 what, address data) external auth {\n if (what == \"hub\") hub = IHubGatewayHandler(data);\n else if (what == \"poolManager\") poolManager = IPoolManagerGatewayHandler(data);\n else if (what == \"investmentManager\") investmentManager = IRequestManagerGatewayHandler(data);\n else if (what == \"balanceSheet\") balanceSheet = IBalanceSheetGatewayHandler(data);\n else revert FileUnrecognizedParam();\n\n emit File(what, data);\n }\n\n //----------------------------------------------------------------------------------------------\n // Helpers\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IMessageDispatcher\n function estimate(uint16 centrifugeId, bytes calldata payload) external view returns (uint256 amount) {\n if (centrifugeId == localCentrifugeId) return 0;\n return gateway.estimate(centrifugeId, payload);\n }\n\n //----------------------------------------------------------------------------------------------\n // Outgoing\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IPoolMessageSender\n function sendNotifyPool(uint16 centrifugeId, PoolId poolId) external auth {\n if (centrifugeId == localCentrifugeId) {\n poolManager.addPool(poolId);\n } else {\n gateway.send(centrifugeId, MessageLib.NotifyPool({poolId: poolId.raw()}).serialize());\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendNotifyShareClass(\n uint16 centrifugeId,\n PoolId poolId,\n ShareClassId scId,\n string memory name,\n string memory symbol,\n uint8 decimals,\n bytes32 salt,\n bytes32 hook\n ) external auth {\n if (centrifugeId == localCentrifugeId) {\n poolManager.addShareClass(poolId, scId, name, symbol, decimals, salt, hook.toAddress());\n } else {\n gateway.send(\n centrifugeId,\n MessageLib.NotifyShareClass({\n poolId: poolId.raw(),\n scId: scId.raw(),\n name: name,\n symbol: symbol.toBytes32(),\n decimals: decimals,\n salt: salt,\n hook: hook\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendNotifyShareMetadata(\n uint16 centrifugeId,\n PoolId poolId,\n ShareClassId scId,\n string memory name,\n string memory symbol\n ) external auth {\n if (centrifugeId == localCentrifugeId) {\n poolManager.updateShareMetadata(poolId, scId, name, symbol);\n } else {\n gateway.send(\n centrifugeId,\n MessageLib.NotifyShareMetadata({\n poolId: poolId.raw(),\n scId: scId.raw(),\n name: name,\n symbol: symbol.toBytes32()\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendUpdateShareHook(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bytes32 hook) external auth {\n if (centrifugeId == localCentrifugeId) {\n poolManager.updateShareHook(poolId, scId, hook.toAddress());\n } else {\n gateway.send(\n centrifugeId,\n MessageLib.UpdateShareHook({poolId: poolId.raw(), scId: scId.raw(), hook: hook}).serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendNotifyPricePoolPerShare(uint16 chainId, PoolId poolId, ShareClassId scId, D18 sharePrice)\n external\n auth\n {\n uint64 timestamp = block.timestamp.toUint64();\n if (chainId == localCentrifugeId) {\n poolManager.updatePricePoolPerShare(poolId, scId, sharePrice.raw(), timestamp);\n } else {\n gateway.send(\n chainId,\n MessageLib.NotifyPricePoolPerShare({\n poolId: poolId.raw(),\n scId: scId.raw(),\n price: sharePrice.raw(),\n timestamp: timestamp\n }).serialize()\n );\n }\n }\n\n function sendNotifyPricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId, D18 price) external auth {\n uint64 timestamp = block.timestamp.toUint64();\n if (assetId.centrifugeId() == localCentrifugeId) {\n poolManager.updatePricePoolPerAsset(poolId, scId, assetId, price.raw(), timestamp);\n } else {\n gateway.send(\n assetId.centrifugeId(),\n MessageLib.NotifyPricePoolPerAsset({\n poolId: poolId.raw(),\n scId: scId.raw(),\n assetId: assetId.raw(),\n price: price.raw(),\n timestamp: timestamp\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendFulfilledDepositRequest(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n bytes32 investor,\n uint128 assetAmount,\n uint128 shareAmount\n ) external auth {\n if (assetId.centrifugeId() == localCentrifugeId) {\n investmentManager.fulfillDepositRequest(\n poolId, scId, investor.toAddress(), assetId, assetAmount, shareAmount\n );\n } else {\n gateway.send(\n assetId.centrifugeId(),\n MessageLib.FulfilledDepositRequest({\n poolId: poolId.raw(),\n scId: scId.raw(),\n investor: investor,\n assetId: assetId.raw(),\n assetAmount: assetAmount,\n shareAmount: shareAmount\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendFulfilledRedeemRequest(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n bytes32 investor,\n uint128 assetAmount,\n uint128 shareAmount\n ) external auth {\n if (assetId.centrifugeId() == localCentrifugeId) {\n investmentManager.fulfillRedeemRequest(\n poolId, scId, investor.toAddress(), assetId, assetAmount, shareAmount\n );\n } else {\n gateway.send(\n assetId.centrifugeId(),\n MessageLib.FulfilledRedeemRequest({\n poolId: poolId.raw(),\n scId: scId.raw(),\n investor: investor,\n assetId: assetId.raw(),\n assetAmount: assetAmount,\n shareAmount: shareAmount\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendFulfilledCancelDepositRequest(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n bytes32 investor,\n uint128 cancelledAmount\n ) external auth {\n if (assetId.centrifugeId() == localCentrifugeId) {\n investmentManager.fulfillCancelDepositRequest(\n poolId, scId, investor.toAddress(), assetId, cancelledAmount, cancelledAmount\n );\n } else {\n gateway.send(\n assetId.centrifugeId(),\n MessageLib.FulfilledCancelDepositRequest({\n poolId: poolId.raw(),\n scId: scId.raw(),\n investor: investor,\n assetId: assetId.raw(),\n cancelledAmount: cancelledAmount\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendFulfilledCancelRedeemRequest(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n bytes32 investor,\n uint128 cancelledShares\n ) external auth {\n if (assetId.centrifugeId() == localCentrifugeId) {\n investmentManager.fulfillCancelRedeemRequest(poolId, scId, investor.toAddress(), assetId, cancelledShares);\n } else {\n gateway.send(\n assetId.centrifugeId(),\n MessageLib.FulfilledCancelRedeemRequest({\n poolId: poolId.raw(),\n scId: scId.raw(),\n investor: investor,\n assetId: assetId.raw(),\n cancelledShares: cancelledShares\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendUpdateRestriction(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bytes calldata payload)\n external\n auth\n {\n if (centrifugeId == localCentrifugeId) {\n poolManager.updateRestriction(poolId, scId, payload);\n } else {\n gateway.send(\n centrifugeId,\n MessageLib.UpdateRestriction({poolId: poolId.raw(), scId: scId.raw(), payload: payload}).serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendUpdateContract(\n uint16 centrifugeId,\n PoolId poolId,\n ShareClassId scId,\n bytes32 target,\n bytes calldata payload\n ) external auth {\n if (centrifugeId == localCentrifugeId) {\n poolManager.updateContract(poolId, scId, target.toAddress(), payload);\n } else {\n gateway.send(\n centrifugeId,\n MessageLib.UpdateContract({poolId: poolId.raw(), scId: scId.raw(), target: target, payload: payload})\n .serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendApprovedDeposits(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n uint128 assetAmount,\n D18 pricePoolPerAsset\n ) external auth {\n if (assetId.centrifugeId() == localCentrifugeId) {\n investmentManager.approvedDeposits(poolId, scId, assetId, assetAmount, pricePoolPerAsset);\n } else {\n gateway.send(\n assetId.centrifugeId(),\n MessageLib.ApprovedDeposits({\n poolId: poolId.raw(),\n scId: scId.raw(),\n assetId: assetId.raw(),\n assetAmount: assetAmount,\n pricePoolPerAsset: pricePoolPerAsset.raw()\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendIssuedShares(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n uint128 shareAmount,\n D18 pricePoolPerShare\n ) external auth {\n if (assetId.centrifugeId() == localCentrifugeId) {\n investmentManager.issuedShares(poolId, scId, shareAmount, pricePoolPerShare);\n } else {\n gateway.send(\n assetId.centrifugeId(),\n MessageLib.IssuedShares({\n poolId: poolId.raw(),\n scId: scId.raw(),\n shareAmount: shareAmount,\n pricePoolPerShare: pricePoolPerShare.raw()\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendRevokedShares(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n uint128 assetAmount,\n uint128 shareAmount,\n D18 pricePoolPerShare\n ) external auth {\n if (assetId.centrifugeId() == localCentrifugeId) {\n investmentManager.revokedShares(poolId, scId, assetId, assetAmount, shareAmount, pricePoolPerShare);\n } else {\n gateway.send(\n assetId.centrifugeId(),\n MessageLib.RevokedShares({\n poolId: poolId.raw(),\n scId: scId.raw(),\n assetId: assetId.raw(),\n assetAmount: assetAmount,\n shareAmount: shareAmount,\n pricePoolPerShare: pricePoolPerShare.raw()\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendTriggerIssueShares(uint16 centrifugeId, PoolId poolId, ShareClassId scId, address who, uint128 shares)\n external\n auth\n {\n if (centrifugeId == localCentrifugeId) {\n balanceSheet.triggerIssueShares(poolId, scId, who, shares);\n } else {\n gateway.send(\n centrifugeId,\n MessageLib.TriggerIssueShares({\n poolId: poolId.raw(),\n scId: scId.raw(),\n who: who.toBytes32(),\n shares: shares\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendTriggerSubmitQueuedShares(uint16 centrifugeId, PoolId poolId, ShareClassId scId) external auth {\n if (centrifugeId == localCentrifugeId) {\n balanceSheet.submitQueuedShares(poolId, scId);\n } else {\n gateway.send(\n centrifugeId, MessageLib.TriggerSubmitQueuedShares({poolId: poolId.raw(), scId: scId.raw()}).serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendTriggerSubmitQueuedAssets(PoolId poolId, ShareClassId scId, AssetId assetId) external auth {\n if (assetId.centrifugeId() == localCentrifugeId) {\n balanceSheet.submitQueuedAssets(poolId, scId, assetId);\n } else {\n gateway.send(\n assetId.centrifugeId(),\n MessageLib.TriggerSubmitQueuedAssets({poolId: poolId.raw(), scId: scId.raw(), assetId: assetId.raw()})\n .serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendSetQueue(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bool enabled) external auth {\n if (centrifugeId == localCentrifugeId) {\n balanceSheet.setQueue(poolId, scId, enabled);\n } else {\n gateway.send(\n centrifugeId,\n MessageLib.SetQueue({poolId: poolId.raw(), scId: scId.raw(), enabled: enabled}).serialize()\n );\n }\n }\n\n /// @inheritdoc IRootMessageSender\n function sendScheduleUpgrade(uint16 centrifugeId, bytes32 target) external auth {\n if (centrifugeId == localCentrifugeId) {\n root.scheduleRely(target.toAddress());\n } else {\n gateway.send(centrifugeId, MessageLib.ScheduleUpgrade({target: target}).serialize());\n }\n }\n\n /// @inheritdoc IRootMessageSender\n function sendCancelUpgrade(uint16 centrifugeId, bytes32 target) external auth {\n if (centrifugeId == localCentrifugeId) {\n root.cancelRely(target.toAddress());\n } else {\n gateway.send(centrifugeId, MessageLib.CancelUpgrade({target: target}).serialize());\n }\n }\n\n /// @inheritdoc IRootMessageSender\n function sendRecoverTokens(\n uint16 centrifugeId,\n bytes32 target,\n bytes32 token,\n uint256 tokenId,\n bytes32 to,\n uint256 amount\n ) external auth {\n if (centrifugeId == localCentrifugeId) {\n tokenRecoverer.recoverTokens(\n IRecoverable(target.toAddress()), token.toAddress(), tokenId, to.toAddress(), amount\n );\n } else {\n gateway.send(\n centrifugeId,\n MessageLib.RecoverTokens({target: target, token: token, tokenId: tokenId, to: to, amount: amount})\n .serialize()\n );\n }\n }\n\n /// @inheritdoc IRootMessageSender\n function sendInitiateRecovery(uint16 centrifugeId, uint16 adapterCentrifugeId, bytes32 adapter, bytes32 hash)\n external\n auth\n {\n if (centrifugeId == localCentrifugeId) {\n gateway.initiateRecovery(adapterCentrifugeId, IAdapter(adapter.toAddress()), hash);\n } else {\n gateway.send(\n centrifugeId,\n MessageLib.InitiateRecovery({hash: hash, adapter: adapter, centrifugeId: adapterCentrifugeId}).serialize(\n )\n );\n }\n }\n\n /// @inheritdoc IRootMessageSender\n function sendDisputeRecovery(uint16 centrifugeId, uint16 adapterCentrifugeId, bytes32 adapter, bytes32 hash)\n external\n auth\n {\n if (centrifugeId == localCentrifugeId) {\n gateway.disputeRecovery(adapterCentrifugeId, IAdapter(adapter.toAddress()), hash);\n } else {\n gateway.send(\n centrifugeId,\n MessageLib.DisputeRecovery({hash: hash, adapter: adapter, centrifugeId: adapterCentrifugeId}).serialize(\n )\n );\n }\n }\n\n /// @inheritdoc IVaultMessageSender\n function sendTransferShares(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bytes32 receiver, uint128 amount)\n external\n auth\n {\n if (centrifugeId == localCentrifugeId) {\n poolManager.handleTransferShares(poolId, scId, receiver.toAddress(), amount);\n } else {\n gateway.send(\n centrifugeId,\n MessageLib.TransferShares({poolId: poolId.raw(), scId: scId.raw(), receiver: receiver, amount: amount})\n .serialize()\n );\n }\n }\n\n /// @inheritdoc IVaultMessageSender\n function sendDepositRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId assetId, uint128 amount)\n external\n auth\n {\n if (poolId.centrifugeId() == localCentrifugeId) {\n hub.depositRequest(poolId, scId, investor, assetId, amount);\n } else {\n gateway.send(\n poolId.centrifugeId(),\n MessageLib.DepositRequest({\n poolId: poolId.raw(),\n scId: scId.raw(),\n investor: investor,\n assetId: assetId.raw(),\n amount: amount\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IVaultMessageSender\n function sendRedeemRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId assetId, uint128 amount)\n external\n auth\n {\n if (poolId.centrifugeId() == localCentrifugeId) {\n hub.redeemRequest(poolId, scId, investor, assetId, amount);\n } else {\n gateway.send(\n poolId.centrifugeId(),\n MessageLib.RedeemRequest({\n poolId: poolId.raw(),\n scId: scId.raw(),\n investor: investor,\n assetId: assetId.raw(),\n amount: amount\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IVaultMessageSender\n function sendCancelDepositRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId assetId)\n external\n auth\n {\n if (poolId.centrifugeId() == localCentrifugeId) {\n hub.cancelDepositRequest(poolId, scId, investor, assetId);\n } else {\n gateway.send(\n poolId.centrifugeId(),\n MessageLib.CancelDepositRequest({\n poolId: poolId.raw(),\n scId: scId.raw(),\n investor: investor,\n assetId: assetId.raw()\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IVaultMessageSender\n function sendCancelRedeemRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId assetId)\n external\n auth\n {\n if (poolId.centrifugeId() == localCentrifugeId) {\n hub.cancelRedeemRequest(poolId, scId, investor, assetId);\n } else {\n gateway.send(\n poolId.centrifugeId(),\n MessageLib.CancelRedeemRequest({\n poolId: poolId.raw(),\n scId: scId.raw(),\n investor: investor,\n assetId: assetId.raw()\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IVaultMessageSender\n function sendUpdateHoldingAmount(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n address provider,\n uint128 amount,\n D18 pricePoolPerAsset,\n bool isIncrease\n ) external auth {\n if (poolId.centrifugeId() == localCentrifugeId) {\n hub.updateHoldingAmount(poolId, scId, assetId, amount, pricePoolPerAsset, isIncrease);\n } else {\n gateway.send(\n poolId.centrifugeId(),\n MessageLib.UpdateHoldingAmount({\n poolId: poolId.raw(),\n scId: scId.raw(),\n assetId: assetId.raw(),\n who: provider.toBytes32(),\n amount: amount,\n pricePerUnit: pricePoolPerAsset.raw(),\n timestamp: uint64(block.timestamp),\n isIncrease: isIncrease\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IVaultMessageSender\n function sendUpdateShares(PoolId poolId, ShareClassId scId, uint128 shares, bool isIssuance) external auth {\n if (poolId.centrifugeId() == localCentrifugeId) {\n if (isIssuance) {\n hub.increaseShareIssuance(poolId, scId, shares);\n } else {\n hub.decreaseShareIssuance(poolId, scId, shares);\n }\n } else {\n gateway.send(\n poolId.centrifugeId(),\n MessageLib.UpdateShares({\n poolId: poolId.raw(),\n scId: scId.raw(),\n shares: shares,\n timestamp: uint64(block.timestamp),\n isIssuance: isIssuance\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IVaultMessageSender\n function sendRegisterAsset(uint16 centrifugeId, AssetId assetId, uint8 decimals) external auth {\n if (centrifugeId == localCentrifugeId) {\n hub.registerAsset(assetId, decimals);\n } else {\n gateway.send(\n centrifugeId, MessageLib.RegisterAsset({assetId: assetId.raw(), decimals: decimals}).serialize()\n );\n }\n }\n}\n" + }, + "src/common/MessageProcessor.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {D18, d18} from \"src/misc/types/D18.sol\";\nimport {IRecoverable} from \"src/misc/interfaces/IRecoverable.sol\";\n\nimport {MessageType, MessageLib} from \"src/common/libraries/MessageLib.sol\";\nimport {IAdapter} from \"src/common/interfaces/IAdapter.sol\";\nimport {IMessageHandler} from \"src/common/interfaces/IMessageHandler.sol\";\nimport {IMessageProcessor} from \"src/common/interfaces/IMessageProcessor.sol\";\nimport {IMessageProperties} from \"src/common/interfaces/IMessageProperties.sol\";\nimport {IRoot} from \"src/common/interfaces/IRoot.sol\";\nimport {\n IGatewayHandler,\n IPoolManagerGatewayHandler,\n IBalanceSheetGatewayHandler,\n IHubGatewayHandler,\n IRequestManagerGatewayHandler\n} from \"src/common/interfaces/IGatewayHandlers.sol\";\n\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ITokenRecoverer} from \"src/common/interfaces/ITokenRecoverer.sol\";\n\ncontract MessageProcessor is Auth, IMessageProcessor {\n using CastLib for *;\n using MessageLib for *;\n using BytesLib for bytes;\n\n IRoot public immutable root;\n ITokenRecoverer public immutable tokenRecoverer;\n\n IGatewayHandler public gateway;\n IHubGatewayHandler public hub;\n IPoolManagerGatewayHandler public poolManager;\n IRequestManagerGatewayHandler public investmentManager;\n IBalanceSheetGatewayHandler public balanceSheet;\n\n constructor(IRoot root_, ITokenRecoverer tokenRecoverer_, address deployer) Auth(deployer) {\n root = root_;\n tokenRecoverer = tokenRecoverer_;\n }\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IMessageProcessor\n function file(bytes32 what, address data) external auth {\n if (what == \"gateway\") gateway = IGatewayHandler(data);\n else if (what == \"hub\") hub = IHubGatewayHandler(data);\n else if (what == \"poolManager\") poolManager = IPoolManagerGatewayHandler(data);\n else if (what == \"investmentManager\") investmentManager = IRequestManagerGatewayHandler(data);\n else if (what == \"balanceSheet\") balanceSheet = IBalanceSheetGatewayHandler(data);\n else revert FileUnrecognizedParam();\n\n emit File(what, data);\n }\n\n //----------------------------------------------------------------------------------------------\n // Handlers\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IMessageHandler\n function handle(uint16, bytes calldata message) external auth {\n MessageType kind = message.messageType();\n\n if (kind == MessageType.InitiateRecovery) {\n MessageLib.InitiateRecovery memory m = message.deserializeInitiateRecovery();\n gateway.initiateRecovery(m.centrifugeId, IAdapter(m.adapter.toAddress()), m.hash);\n } else if (kind == MessageType.DisputeRecovery) {\n MessageLib.DisputeRecovery memory m = message.deserializeDisputeRecovery();\n gateway.disputeRecovery(m.centrifugeId, IAdapter(m.adapter.toAddress()), m.hash);\n } else if (kind == MessageType.ScheduleUpgrade) {\n MessageLib.ScheduleUpgrade memory m = message.deserializeScheduleUpgrade();\n root.scheduleRely(m.target.toAddress());\n } else if (kind == MessageType.CancelUpgrade) {\n MessageLib.CancelUpgrade memory m = message.deserializeCancelUpgrade();\n root.cancelRely(m.target.toAddress());\n } else if (kind == MessageType.RecoverTokens) {\n MessageLib.RecoverTokens memory m = message.deserializeRecoverTokens();\n tokenRecoverer.recoverTokens(\n IRecoverable(m.target.toAddress()), m.token.toAddress(), m.tokenId, m.to.toAddress(), m.amount\n );\n } else if (kind == MessageType.RegisterAsset) {\n MessageLib.RegisterAsset memory m = message.deserializeRegisterAsset();\n hub.registerAsset(AssetId.wrap(m.assetId), m.decimals);\n } else if (kind == MessageType.NotifyPool) {\n poolManager.addPool(PoolId.wrap(MessageLib.deserializeNotifyPool(message).poolId));\n } else if (kind == MessageType.NotifyShareClass) {\n MessageLib.NotifyShareClass memory m = MessageLib.deserializeNotifyShareClass(message);\n poolManager.addShareClass(\n PoolId.wrap(m.poolId),\n ShareClassId.wrap(m.scId),\n m.name,\n m.symbol.toString(),\n m.decimals,\n m.salt,\n m.hook.toAddress()\n );\n } else if (kind == MessageType.NotifyPricePoolPerShare) {\n MessageLib.NotifyPricePoolPerShare memory m = MessageLib.deserializeNotifyPricePoolPerShare(message);\n poolManager.updatePricePoolPerShare(PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.price, m.timestamp);\n } else if (kind == MessageType.NotifyPricePoolPerAsset) {\n MessageLib.NotifyPricePoolPerAsset memory m = MessageLib.deserializeNotifyPricePoolPerAsset(message);\n poolManager.updatePricePoolPerAsset(\n PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), AssetId.wrap(m.assetId), m.price, m.timestamp\n );\n } else if (kind == MessageType.NotifyShareMetadata) {\n MessageLib.NotifyShareMetadata memory m = MessageLib.deserializeNotifyShareMetadata(message);\n poolManager.updateShareMetadata(\n PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.name, m.symbol.toString()\n );\n } else if (kind == MessageType.UpdateShareHook) {\n MessageLib.UpdateShareHook memory m = MessageLib.deserializeUpdateShareHook(message);\n poolManager.updateShareHook(PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.hook.toAddress());\n } else if (kind == MessageType.TransferShares) {\n MessageLib.TransferShares memory m = MessageLib.deserializeTransferShares(message);\n poolManager.handleTransferShares(\n PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.receiver.toAddress(), m.amount\n );\n } else if (kind == MessageType.UpdateRestriction) {\n MessageLib.UpdateRestriction memory m = MessageLib.deserializeUpdateRestriction(message);\n poolManager.updateRestriction(PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.payload);\n } else if (kind == MessageType.UpdateContract) {\n MessageLib.UpdateContract memory m = MessageLib.deserializeUpdateContract(message);\n poolManager.updateContract(\n PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.target.toAddress(), m.payload\n );\n } else if (kind == MessageType.DepositRequest) {\n MessageLib.DepositRequest memory m = message.deserializeDepositRequest();\n hub.depositRequest(\n PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.investor, AssetId.wrap(m.assetId), m.amount\n );\n } else if (kind == MessageType.RedeemRequest) {\n MessageLib.RedeemRequest memory m = message.deserializeRedeemRequest();\n hub.redeemRequest(\n PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.investor, AssetId.wrap(m.assetId), m.amount\n );\n } else if (kind == MessageType.CancelDepositRequest) {\n MessageLib.CancelDepositRequest memory m = message.deserializeCancelDepositRequest();\n hub.cancelDepositRequest(\n PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.investor, AssetId.wrap(m.assetId)\n );\n } else if (kind == MessageType.CancelRedeemRequest) {\n MessageLib.CancelRedeemRequest memory m = message.deserializeCancelRedeemRequest();\n hub.cancelRedeemRequest(\n PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.investor, AssetId.wrap(m.assetId)\n );\n } else if (kind == MessageType.FulfilledDepositRequest) {\n MessageLib.FulfilledDepositRequest memory m = message.deserializeFulfilledDepositRequest();\n investmentManager.fulfillDepositRequest(\n PoolId.wrap(m.poolId),\n ShareClassId.wrap(m.scId),\n m.investor.toAddress(),\n AssetId.wrap(m.assetId),\n m.assetAmount,\n m.shareAmount\n );\n } else if (kind == MessageType.FulfilledRedeemRequest) {\n MessageLib.FulfilledRedeemRequest memory m = message.deserializeFulfilledRedeemRequest();\n investmentManager.fulfillRedeemRequest(\n PoolId.wrap(m.poolId),\n ShareClassId.wrap(m.scId),\n m.investor.toAddress(),\n AssetId.wrap(m.assetId),\n m.assetAmount,\n m.shareAmount\n );\n } else if (kind == MessageType.FulfilledCancelDepositRequest) {\n MessageLib.FulfilledCancelDepositRequest memory m = message.deserializeFulfilledCancelDepositRequest();\n investmentManager.fulfillCancelDepositRequest(\n PoolId.wrap(m.poolId),\n ShareClassId.wrap(m.scId),\n m.investor.toAddress(),\n AssetId.wrap(m.assetId),\n m.cancelledAmount,\n m.cancelledAmount\n );\n } else if (kind == MessageType.FulfilledCancelRedeemRequest) {\n MessageLib.FulfilledCancelRedeemRequest memory m = message.deserializeFulfilledCancelRedeemRequest();\n investmentManager.fulfillCancelRedeemRequest(\n PoolId.wrap(m.poolId),\n ShareClassId.wrap(m.scId),\n m.investor.toAddress(),\n AssetId.wrap(m.assetId),\n m.cancelledShares\n );\n } else if (kind == MessageType.TriggerIssueShares) {\n MessageLib.TriggerIssueShares memory m = message.deserializeTriggerIssueShares();\n balanceSheet.triggerIssueShares(\n PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.who.toAddress(), m.shares\n );\n } else if (kind == MessageType.UpdateHoldingAmount) {\n MessageLib.UpdateHoldingAmount memory m = message.deserializeUpdateHoldingAmount();\n hub.updateHoldingAmount(\n PoolId.wrap(m.poolId),\n ShareClassId.wrap(m.scId),\n AssetId.wrap(m.assetId),\n m.amount,\n D18.wrap(m.pricePerUnit),\n m.isIncrease\n );\n } else if (kind == MessageType.UpdateShares) {\n MessageLib.UpdateShares memory m = message.deserializeUpdateShares();\n if (m.isIssuance) {\n hub.increaseShareIssuance(PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.shares);\n } else {\n hub.decreaseShareIssuance(PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.shares);\n }\n } else if (kind == MessageType.ApprovedDeposits) {\n MessageLib.ApprovedDeposits memory m = message.deserializeApprovedDeposits();\n investmentManager.approvedDeposits(\n PoolId.wrap(m.poolId),\n ShareClassId.wrap(m.scId),\n AssetId.wrap(m.assetId),\n m.assetAmount,\n D18.wrap(m.pricePoolPerAsset)\n );\n } else if (kind == MessageType.IssuedShares) {\n MessageLib.IssuedShares memory m = message.deserializeIssuedShares();\n investmentManager.issuedShares(\n PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.shareAmount, D18.wrap(m.pricePoolPerShare)\n );\n } else if (kind == MessageType.RevokedShares) {\n MessageLib.RevokedShares memory m = message.deserializeRevokedShares();\n investmentManager.revokedShares(\n PoolId.wrap(m.poolId),\n ShareClassId.wrap(m.scId),\n AssetId.wrap(m.assetId),\n m.assetAmount,\n m.shareAmount,\n D18.wrap(m.pricePoolPerShare)\n );\n } else if (kind == MessageType.TriggerSubmitQueuedShares) {\n MessageLib.TriggerSubmitQueuedShares memory m = message.deserializeTriggerSubmitQueuedShares();\n balanceSheet.submitQueuedShares(PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId));\n } else if (kind == MessageType.TriggerSubmitQueuedAssets) {\n MessageLib.TriggerSubmitQueuedAssets memory m = message.deserializeTriggerSubmitQueuedAssets();\n balanceSheet.submitQueuedAssets(PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), AssetId.wrap(m.assetId));\n } else if (kind == MessageType.SetQueue) {\n MessageLib.SetQueue memory m = message.deserializeSetQueue();\n balanceSheet.setQueue(PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.enabled);\n } else {\n revert InvalidMessage(uint8(kind));\n }\n }\n\n /// @inheritdoc IMessageProperties\n function isMessageRecovery(bytes calldata message) external pure returns (bool) {\n uint8 code = message.messageCode();\n return code == uint8(MessageType.InitiateRecovery) || code == uint8(MessageType.DisputeRecovery);\n }\n\n /// @inheritdoc IMessageProperties\n function messageLength(bytes calldata message) external pure returns (uint16) {\n return message.messageLength();\n }\n\n /// @inheritdoc IMessageProperties\n function messagePoolId(bytes calldata message) external pure returns (PoolId) {\n return message.messagePoolId();\n }\n}\n" + }, + "src/common/Root.sol": { + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {IAuth} from \"src/misc/interfaces/IAuth.sol\";\n\nimport {IRoot} from \"src/common/interfaces/IRoot.sol\";\n\n/// @title Root\n/// @notice Core contract that is a ward on all other deployed contracts.\n/// @dev Pausing can happen instantaneously, but relying on other contracts\n/// is restricted to the timelock set by the delay.\ncontract Root is Auth, IRoot {\n /// @dev To prevent filing a delay that would block any updates indefinitely\n uint256 internal constant MAX_DELAY = 4 weeks;\n\n bool public paused;\n uint256 public delay;\n mapping(address => uint256) public endorsements;\n mapping(address relyTarget => uint256 timestamp) public schedule;\n\n constructor(uint256 _delay, address deployer) Auth(deployer) {\n require(_delay <= MAX_DELAY, DelayTooLong());\n delay = _delay;\n }\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IRoot\n function file(bytes32 what, uint256 data) external auth {\n if (what == \"delay\") {\n require(data <= MAX_DELAY, DelayTooLong());\n delay = data;\n } else {\n revert FileUnrecognizedParam();\n }\n emit File(what, data);\n }\n\n /// @inheritdoc IRoot\n function endorse(address user) external auth {\n endorsements[user] = 1;\n emit Endorse(user);\n }\n\n /// @inheritdoc IRoot\n function veto(address user) external auth {\n endorsements[user] = 0;\n emit Veto(user);\n }\n\n /// @inheritdoc IRoot\n function endorsed(address user) external view returns (bool) {\n return endorsements[user] == 1;\n }\n\n //----------------------------------------------------------------------------------------------\n // Pause management\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IRoot\n function pause() external auth {\n paused = true;\n emit Pause();\n }\n\n /// @inheritdoc IRoot\n function unpause() external auth {\n paused = false;\n emit Unpause();\n }\n\n //----------------------------------------------------------------------------------------------\n // Timelocked ward management\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IRoot\n function scheduleRely(address target) external auth {\n schedule[target] = block.timestamp + delay;\n emit ScheduleRely(target, schedule[target]);\n }\n\n /// @inheritdoc IRoot\n function cancelRely(address target) external auth {\n require(schedule[target] != 0, TargetNotScheduled());\n schedule[target] = 0;\n emit CancelRely(target);\n }\n\n /// @inheritdoc IRoot\n function executeScheduledRely(address target) external {\n require(schedule[target] != 0, TargetNotScheduled());\n require(schedule[target] <= block.timestamp, TargetNotReady());\n\n wards[target] = 1;\n emit Rely(target);\n\n schedule[target] = 0;\n }\n\n //----------------------------------------------------------------------------------------------\n // External contract ward management\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IRoot\n function relyContract(address target, address user) external auth {\n IAuth(target).rely(user);\n emit RelyContract(target, user);\n }\n\n /// @inheritdoc IRoot\n function denyContract(address target, address user) external auth {\n IAuth(target).deny(user);\n emit DenyContract(target, user);\n }\n}\n" + }, + "src/common/TokenRecoverer.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {IRecoverable} from \"src/misc/interfaces/IRecoverable.sol\";\n\nimport {IRoot} from \"src/common/interfaces/IRoot.sol\";\nimport {ITokenRecoverer} from \"src/common/interfaces/ITokenRecoverer.sol\";\nimport {IRecoverable} from \"src/misc/interfaces/IRecoverable.sol\";\n\ncontract TokenRecoverer is Auth, ITokenRecoverer {\n IRoot public immutable root;\n\n constructor(IRoot root_, address deployer) Auth(deployer) {\n root = root_;\n }\n\n /// @notice inheritdoc ITokenRecoverer\n function recoverTokens(IRecoverable target, address token, uint256 tokenId, address to, uint256 amount)\n external\n auth\n {\n root.relyContract(address(target), address(this));\n\n if (tokenId == 0) {\n target.recoverTokens(token, to, amount);\n } else {\n target.recoverTokens(token, tokenId, to, amount);\n }\n\n root.denyContract(address(target), address(this));\n\n emit RecoverTokens(target, token, tokenId, to, amount);\n }\n}\n" + }, + "src/common/adapters/AxelarAdapter.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {\n IAxelarAdapter,\n IAdapter,\n IAxelarGateway,\n IAxelarGasService,\n AxelarSource,\n AxelarDestination,\n IAxelarExecutable\n} from \"src/common/interfaces/IAxelarAdapter.sol\";\nimport {IMessageHandler} from \"src/common/interfaces/IMessageHandler.sol\";\n\n/// @title Axelar Adapter\n/// @notice Routing contract that integrates with an Axelar Gateway\ncontract AxelarAdapter is Auth, IAxelarAdapter {\n using CastLib for *;\n\n IMessageHandler public immutable gateway;\n IAxelarGateway public immutable axelarGateway;\n IAxelarGasService public immutable axelarGasService;\n\n mapping(string axelarId => AxelarSource) public sources;\n mapping(uint16 centrifugeId => AxelarDestination) public destinations;\n\n constructor(IMessageHandler gateway_, address axelarGateway_, address axelarGasService_, address deployer)\n Auth(deployer)\n {\n gateway = gateway_;\n axelarGateway = IAxelarGateway(axelarGateway_);\n axelarGasService = IAxelarGasService(axelarGasService_);\n }\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IAxelarAdapter\n function file(bytes32 what, string calldata axelarId, uint16 centrifugeId, string calldata source) external auth {\n if (what == \"sources\") sources[axelarId] = AxelarSource(centrifugeId, keccak256(bytes(source)));\n else revert FileUnrecognizedParam();\n emit File(what, axelarId, centrifugeId, source);\n }\n\n /// @inheritdoc IAxelarAdapter\n function file(bytes32 what, uint16 centrifugeId, string calldata axelarId, string calldata destination)\n external\n auth\n {\n if (what == \"destinations\") destinations[centrifugeId] = AxelarDestination(axelarId, destination);\n else revert FileUnrecognizedParam();\n emit File(what, centrifugeId, axelarId, destination);\n }\n\n //----------------------------------------------------------------------------------------------\n // Incoming\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IAxelarExecutable\n function execute(\n bytes32 commandId,\n string calldata sourceAxelarId,\n string calldata sourceAddress,\n bytes calldata payload\n ) public {\n AxelarSource memory source = sources[sourceAxelarId];\n require(\n source.addressHash != bytes32(\"\") && source.addressHash == keccak256(bytes(sourceAddress)), InvalidAddress()\n );\n\n require(\n axelarGateway.validateContractCall(commandId, sourceAxelarId, sourceAddress, keccak256(payload)),\n NotApprovedByGateway()\n );\n\n gateway.handle(source.centrifugeId, payload);\n }\n\n //----------------------------------------------------------------------------------------------\n // Outgoing\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IAdapter\n function send(uint16 centrifugeId, bytes calldata payload, uint256, /* gasLimit */ address refund)\n external\n payable\n returns (bytes32 adapterData)\n {\n require(msg.sender == address(gateway), NotGateway());\n AxelarDestination memory destination = destinations[centrifugeId];\n require(bytes(destination.axelarId).length != 0, UnknownChainId());\n\n axelarGasService.payNativeGasForContractCall{value: msg.value}(\n address(this), destination.axelarId, destination.addr, payload, refund\n );\n\n axelarGateway.callContract(destination.axelarId, destination.addr, payload);\n\n adapterData = bytes32(\"\");\n }\n\n /// @inheritdoc IAdapter\n function estimate(uint16 centrifugeId, bytes calldata payload, uint256 gasLimit) public view returns (uint256) {\n AxelarDestination memory destination = destinations[centrifugeId];\n return axelarGasService.estimateGasFee(destination.axelarId, destination.addr, payload, gasLimit, bytes(\"\"));\n }\n}\n" + }, + "src/common/adapters/WormholeAdapter.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {IMessageHandler} from \"src/common/interfaces/IMessageHandler.sol\";\nimport {\n IWormholeAdapter,\n IAdapter,\n IWormholeRelayer,\n IWormholeDeliveryProvider,\n IWormholeReceiver,\n WormholeSource,\n WormholeDestination\n} from \"src/common/interfaces/IWormholeAdapter.sol\";\n\n/// @title Wormhole Adapter\n/// @notice Routing contract that integrates with the Wormhole Relayer service\ncontract WormholeAdapter is Auth, IWormholeAdapter {\n using CastLib for bytes32;\n\n uint16 public immutable localWormholeId;\n IMessageHandler public immutable gateway;\n IWormholeRelayer public immutable relayer;\n\n mapping(uint16 wormholeId => WormholeSource) public sources;\n mapping(uint16 centrifugeId => WormholeDestination) public destinations;\n\n constructor(IMessageHandler gateway_, address relayer_, address deployer) Auth(deployer) {\n gateway = gateway_;\n relayer = IWormholeRelayer(relayer_);\n\n IWormholeDeliveryProvider deliveryProvider = IWormholeDeliveryProvider(relayer.getDefaultDeliveryProvider());\n localWormholeId = deliveryProvider.chainId();\n }\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IWormholeAdapter\n function file(bytes32 what, uint16 centrifugeId, uint16 wormholeId, address addr) external auth {\n if (what == \"sources\") sources[wormholeId] = WormholeSource(centrifugeId, addr);\n else if (what == \"destinations\") destinations[centrifugeId] = WormholeDestination(wormholeId, addr);\n else revert FileUnrecognizedParam();\n emit File(what, centrifugeId, wormholeId, addr);\n }\n\n //----------------------------------------------------------------------------------------------\n // Incoming\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IWormholeReceiver\n function receiveWormholeMessages(\n bytes memory payload,\n bytes[] memory, /* additionalVaas */\n bytes32 sourceAddress,\n uint16 sourceWormholeId,\n bytes32 /* deliveryHash */\n ) external payable {\n WormholeSource memory source = sources[sourceWormholeId];\n require(source.addr != address(0) && source.addr == sourceAddress.toAddressLeftPadded(), InvalidSource());\n require(msg.sender == address(relayer), NotWormholeRelayer());\n\n gateway.handle(source.centrifugeId, payload);\n }\n\n //----------------------------------------------------------------------------------------------\n // Outgoing\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IAdapter\n function send(uint16 centrifugeId, bytes calldata payload, uint256 gasLimit, address refund)\n external\n payable\n returns (bytes32 adapterData)\n {\n require(msg.sender == address(gateway), NotGateway());\n WormholeDestination memory destination = destinations[centrifugeId];\n require(destination.wormholeId != 0, UnknownChainId());\n\n uint64 sequence = relayer.sendPayloadToEvm{value: msg.value}(\n destination.wormholeId, destination.addr, payload, 0, gasLimit, localWormholeId, refund\n );\n\n adapterData = bytes32(bytes8(sequence));\n }\n\n /// @inheritdoc IAdapter\n function estimate(uint16 centrifugeId, bytes calldata, uint256 gasLimit)\n public\n view\n returns (uint256 nativePriceQuote)\n {\n (nativePriceQuote,) = relayer.quoteEVMDeliveryPrice(destinations[centrifugeId].wormholeId, 0, gasLimit);\n }\n}\n" + }, + "src/common/interfaces/IAdapter.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IAuth} from \"src/misc/interfaces/IAuth.sol\";\n\ninterface IAdapter is IAuth {\n error NotGateway();\n error UnknownChainId();\n\n /// @notice Send a payload to the destination chain\n function send(uint16 centrifugeId, bytes calldata payload, uint256 gasLimit, address refund)\n external\n payable\n returns (bytes32 adapterData);\n\n /// @notice Estimate the total cost in native gas tokens\n function estimate(uint16 centrifugeId, bytes calldata payload, uint256 gasLimit) external view returns (uint256);\n}\n" + }, + "src/common/interfaces/IAxelarAdapter.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IAdapter} from \"src/common/interfaces/IAdapter.sol\";\n\n// From https://github.com/axelarnetwork/axelar-cgp-solidity/blob/main/contracts/interfaces/IAxelarGateway.sol\ninterface IAxelarGateway {\n function callContract(string calldata destinationChain, string calldata contractAddress, bytes calldata payload)\n external;\n\n function validateContractCall(\n bytes32 commandId,\n string calldata sourceChain,\n string calldata sourceAddress,\n bytes32 payloadHash\n ) external returns (bool);\n}\n\ninterface IAxelarGasService {\n // From\n // https://github.com/axelarnetwork/axelar-gmp-sdk-solidity/blob/00682b6c3db0cc922ec0c4ea3791852c93d7ae31/contracts/gas-estimation/InterchainGasEstimation.sol#L48\n function estimateGasFee(\n string calldata destinationChain,\n string calldata destinationAddress,\n bytes calldata payload,\n uint256 executionGasLimit,\n bytes calldata params\n ) external view returns (uint256 gasEstimate);\n\n // From https://github.com/axelarnetwork/axelar-cgp-solidity/blob/main/contracts/interfaces/IAxelarGasService.sol\n function payNativeGasForContractCall(\n address sender,\n string calldata destinationChain,\n string calldata destinationAddress,\n bytes calldata payload,\n address refundAddress\n ) external payable;\n}\n\n// From\n// https://github.com/axelarnetwork/axelar-gmp-sdk-solidity/blob/00682b6c3db0cc922ec0c4ea3791852c93d7ae31/contracts/interfaces/IAxelarExecutable.sol#L14\ninterface IAxelarExecutable {\n /**\n * @dev Thrown when a function is called with an invalid address.\n */\n error InvalidAddress();\n\n /**\n * @dev Thrown when the call is not approved by the Axelar Gateway.\n */\n error NotApprovedByGateway();\n\n /**\n * @notice Executes the specified command sent from another chain.\n * @dev This function is called by the Axelar Gateway to carry out cross-chain commands.\n * Reverts if the call is not approved by the gateway or other checks fail.\n * @param commandId The identifier of the command to execute.\n * @param sourceChain The name of the source chain from where the command originated.\n * @param sourceAddress The address on the source chain that sent the command.\n * @param payload The payload of the command to be executed. This typically includes the function selector and\n * encoded arguments.\n */\n function execute(\n bytes32 commandId,\n string calldata sourceChain,\n string calldata sourceAddress,\n bytes calldata payload\n ) external;\n}\n\nstruct AxelarSource {\n uint16 centrifugeId;\n bytes32 addressHash;\n}\n\nstruct AxelarDestination {\n string axelarId;\n string addr;\n}\n\ninterface IAxelarAdapter is IAdapter, IAxelarExecutable {\n event File(bytes32 indexed what, string axelarId, uint16 centrifugeId, string source);\n event File(bytes32 indexed what, uint16 centrifugeId, string axelarId, string destination);\n\n error FileUnrecognizedParam();\n\n function file(bytes32 what, string calldata axelarId, uint16 centrifugeId, string calldata source) external;\n function file(bytes32 what, uint16 centrifugeId, string calldata axelarId, string calldata destination) external;\n}\n" + }, + "src/common/interfaces/IGasService.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\ninterface IGasService {\n /// @notice Gas limit for the execution cost of an individual message in a remote chain.\n /// @dev NOTE: In the future we could want to dispatch:\n /// - by destination chain (for non-EVM chains)\n /// - by message type\n /// - by inspecting the payload checking different subsmessages that alter the endpoint processing\n /// @param centrifugeId Where to the cost is defined\n /// @param message Individual message\n /// @return Estimated cost in WEI units\n function gasLimit(uint16 centrifugeId, bytes calldata message) external view returns (uint128);\n\n /// @notice Gas limit for the execution cost of a batch in a remote chain.\n /// @param centrifugeId Where to the cost is defined\n /// @return Max cost in WEI units\n function maxBatchSize(uint16 centrifugeId) external view returns (uint128);\n}\n" + }, + "src/common/interfaces/IGateway.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IRecoverable} from \"src/misc/interfaces/IRecoverable.sol\";\n\nimport {IGatewayHandler} from \"src/common/interfaces/IGatewayHandlers.sol\";\nimport {IMessageHandler} from \"src/common/interfaces/IMessageHandler.sol\";\nimport {IMessageSender} from \"src/common/interfaces/IMessageSender.sol\";\nimport {IAdapter} from \"src/common/interfaces/IAdapter.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\n\nuint8 constant MAX_ADAPTER_COUNT = 8;\n\n/// @notice Interface for dispatch-only gateway\ninterface IGateway is IMessageHandler, IMessageSender, IGatewayHandler {\n /// @dev Each adapter struct is packed with the quorum to reduce SLOADs on handle\n struct Adapter {\n /// @notice Starts at 1 and maps to id - 1 as the index on the adapters array\n uint8 id;\n /// @notice Number of votes required for a message to be executed\n uint8 quorum;\n /// @notice Each time the quorum is decreased, a new session starts which invalidates old votes\n uint64 activeSessionId;\n }\n\n struct InboundBatch {\n /// @dev Counts are stored as integers (instead of boolean values) to accommodate duplicate\n /// messages (e.g. two investments from the same user with the same amount) being\n /// processed in parallel. The entire struct is packed in a single bytes32 slot.\n /// Max uint16 = 65,535 so at most 65,535 duplicate messages can be processed in parallel.\n uint16[MAX_ADAPTER_COUNT] votes;\n /// @notice Each time adapters are updated, a new session starts which invalidates old votes\n uint64 sessionId;\n bytes pendingBatch;\n }\n\n struct Funds {\n /// @notice Funds associated to pay for sending messages\n /// @dev Overflows with type(uint64).max / 10**18 = 7.923 × 10^10 ETH\n uint96 value;\n /// @notice Address where to refund the remaining gas\n IRecoverable refund;\n }\n\n // Used to bypass stack too deep issue\n struct SendData {\n bytes32 batchHash;\n bytes32 payloadId;\n uint256[] gasCost;\n }\n\n struct Underpaid {\n uint128 counter;\n uint128 gasLimit;\n }\n\n // --- Events ---\n event PrepareMessage(uint16 indexed centrifugeId, PoolId poolId, bytes message);\n event UnderpaidBatch(uint16 indexed centrifugeId, bytes batch);\n event RepayBatch(uint16 indexed centrifugeId, bytes batch);\n event SendBatch(\n uint16 indexed centrifugeId,\n bytes32 indexed payloadId,\n bytes batch,\n IAdapter adapter,\n bytes32 adapterData,\n address refund\n );\n event SendProof(\n uint16 indexed centrifugeId, bytes32 indexed payloadId, bytes32 batchHash, IAdapter adapter, bytes32 adapterData\n );\n event HandleBatch(uint16 indexed centrifugeId, bytes32 indexed payloadId, bytes batch, IAdapter adapter);\n event HandleProof(uint16 indexed centrifugeId, bytes32 indexed payloadId, bytes32 batchHash, IAdapter adapter);\n event ExecuteMessage(uint16 indexed centrifugeId, bytes message);\n event FailMessage(uint16 indexed centrifugeId, bytes message, bytes error);\n\n event RecoverMessage(IAdapter adapter, bytes message);\n event RecoverProof(IAdapter adapter, bytes32 batchHash);\n event InitiateRecovery(uint16 centrifugeId, bytes32 batchHash, IAdapter adapter);\n event DisputeRecovery(uint16 centrifugeId, bytes32 batchHash, IAdapter adapter);\n event ExecuteRecovery(uint16 centrifugeId, bytes message, IAdapter adapter);\n\n event File(bytes32 indexed what, uint16 centrifugeId, IAdapter[] adapters);\n event File(bytes32 indexed what, address addr);\n\n event SetRefundAddress(PoolId poolId, IRecoverable refund);\n event SubsidizePool(PoolId indexed poolId, address indexed sender, uint256 amount);\n\n /// @notice Dispatched when the `what` parameter of `file()` is not supported by the implementation.\n error FileUnrecognizedParam();\n\n /// @notice Dispatched when the batch is ended without starting it.\n error NoBatched();\n\n /// @notice Dispatched when the gateway is paused.\n error Paused();\n\n /// @notice Dispatched when the gateway is configured with a number of adapter exceeding the maximum.\n error ExceedsMax();\n\n /// @notice Dispatched when the gateway is configured with an empty adapter set.\n error EmptyAdapterSet();\n\n /// @notice Dispatched when the gateway is configured with duplicate adapters.\n error NoDuplicatesAllowed();\n\n /// @notice Dispatched when the gateway tries to handle a message from an adaptet not contained in the adapter set.\n error InvalidAdapter();\n\n /// @notice Dispatched when the gateway tries to recover a recovery message, which is not allowed.\n error RecoveryPayloadRecovered();\n\n /// @notice Dispatched when the gateway tries to handle a proof from a non proof adapter.\n error NonProofAdapter();\n\n /// @notice Dispatched when the gateway tries to handle a batch from a non message adapter.\n error NonBatchAdapter();\n\n /// @notice Dispatched when a recovery message is executed without being initiated.\n error RecoveryNotInitiated();\n\n /// @notice Dispatched when a recovery message is executed without waiting the challenge period.\n error RecoveryChallengePeriodNotEnded();\n\n /// @notice Dispatched when a the gateway tries to send an empty message.\n error EmptyMessage();\n\n /// @notice Dispatched when a the gateway has not enough fuel to send a message.\n /// Only dispatched in PayTransaction method\n error NotEnoughTransactionGas();\n\n /// @notice Dispatched when a message that has not failed is retried.\n error NotFailedMessage();\n\n /// @notice Dispatched when a batch that has not been underpaid is repaid.\n error NotUnderpaidBatch();\n\n /// @notice Dispatched when a batch is repaid with insufficient funds.\n error InsufficientFundsForRepayment();\n\n /// @notice Dispatched when a message is added to a batch that causes it to exceed the max batch size.\n error ExceedsMaxBatchSize();\n\n /// @notice Dispatched when a refund address is not set.\n error RefundAddressNotSet();\n\n // --- Administration ---\n /// @notice Used to update an array of addresses ( state variable ) on very rare occasions.\n /// @dev Currently it is used to update the supported adapters.\n /// @param what The name of the variable to be updated.\n /// @param centrifugeId Chain where the adapters are associated to.\n /// @param value New addresses.\n function file(bytes32 what, uint16 centrifugeId, IAdapter[] calldata value) external;\n\n /// @notice Used to update an address ( state variable ) on very rare occasions.\n /// @dev Currently used to update addresses of contract instances.\n /// @param what The name of the variable to be updated.\n /// @param data New address.\n function file(bytes32 what, address data) external;\n\n /// @notice Repay an underpaid batch. Send unused funds to subsidy pot of the pool.\n function repay(uint16 centrifugeId, bytes memory batch) external payable;\n\n /// @notice Retry a failed message.\n function retry(uint16 centrifugeId, bytes memory message) external;\n\n /// @notice Set the refund address for message associated to a poolId\n function setRefundAddress(PoolId poolId, IRecoverable refund) external;\n\n /// @notice Pay upfront to later be able to subsidize messages associated to a pool\n function subsidizePool(PoolId poolId) external payable;\n\n /// @notice Prepays for the TX cost for sending the messages through the adapters\n /// Currently being called from Vault Router only.\n /// In order to prepay, the method MUST be called with `msg.value`.\n /// Called is assumed to have called IGateway.estimate before calling this.\n function payTransaction(address payer) external payable;\n\n /// @notice Initialize batching message\n function startBatching() external;\n\n /// @notice Finalize batching messages and send the resulting batch message\n function endBatching() external;\n\n /// @notice Execute message recovery. After the challenge period, the recovery can be executed.\n /// If a malign adapter initiates message recovery,\n /// governance can dispute and immediately cancel the recovery, using any other valid adapter.\n ///\n /// Only 1 recovery can be outstanding per message hash. If multiple adapters fail at the same time,\n /// these will need to be recovered serially (increasing the challenge period for each failed adapter).\n /// @param centrifugeId Chain where the adapter is configured for\n /// @param adapter Adapter's address that the recovery is targeting\n /// @param message Hash of the message to be recovered\n function executeRecovery(uint16 centrifugeId, IAdapter adapter, bytes calldata message) external;\n\n // --- Helpers ---\n /// @notice A view method of the current quorum.abi\n /// @dev Quorum shows the amount of votes needed in order for a message to be dispatched further.\n /// The quorum is taken from the first adapter which is always the length of active adapters.\n /// @param centrifugeId Chain where the adapter is configured for\n /// return Needed amount\n function quorum(uint16 centrifugeId) external view returns (uint8);\n\n /// @notice Gets the current active routers session id.\n /// @dev When the adapters are updated with new ones,\n /// each new set of adapters has their own sessionId.\n /// Currently it uses sessionId of the previous set and\n /// increments it by 1. The idea of an activeSessionId is\n /// to invalidate any incoming messages from previously used adapters.\n /// @param centrifugeId Chain where the adapter is configured for\n function activeSessionId(uint16 centrifugeId) external view returns (uint64);\n\n /// @notice Counts how many times each incoming messages has been received per adapter.\n /// @dev It supports parallel messages ( duplicates ). That means that the incoming messages could be\n /// the result of two or more independ request from the user of the same type.\n /// i.e. Same user would like to deposit same underlying asset with the same amount more then once.\n /// @param centrifugeId Chain where the adapter is configured for\n /// @param batchHash The hash value of the incoming batch message.\n function votes(uint16 centrifugeId, bytes32 batchHash) external view returns (uint16[MAX_ADAPTER_COUNT] memory);\n\n /// @notice Used to calculate overall cost for bridging a payload on the first adapter and settling\n /// on the destination chain and bridging its payload proofs on n-1 adapter\n /// and settling on the destination chain.\n /// @param payload Used in gas cost calculations.\n /// @dev Currenly the payload is not taken into consideration.\n /// @return total Total cost for sending one message and corresponding proofs on through all adapters\n function estimate(uint16 centrifugeId, bytes calldata payload) external view returns (uint256 total);\n\n /// @notice Returns the address of the adapter at the given id.\n /// @param centrifugeId Chain where the adapter is configured for\n function adapters(uint16 centrifugeId, uint256 id) external view returns (IAdapter);\n\n /// @notice Returns the timestamp when the given recovery can be executed.\n /// @param centrifugeId Chain where the adapter is configured for\n function recoveries(uint16 centrifugeId, IAdapter adapter, bytes32 batchHash)\n external\n view\n returns (uint256 timestamp);\n\n /// @notice Returns the current gateway batching level.\n function isBatching() external view returns (bool);\n}\n" + }, + "src/common/interfaces/IGatewayHandlers.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {D18} from \"src/misc/types/D18.sol\";\n\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {IAdapter} from \"src/common/interfaces/IAdapter.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\n\n/// -----------------------------------------------------\n/// Common Handlers\n/// -----------------------------------------------------\n/// @notice Interface for Gateway methods called by messages\ninterface IGatewayHandler {\n /// @notice Initialize the recovery of a payload.\n /// @param centrifugeId Chain where the adapter is configured for\n /// @param adapter Adapter that the recovery was targeting\n /// @param payloadHash Hash of the payload being disputed\n function initiateRecovery(uint16 centrifugeId, IAdapter adapter, bytes32 payloadHash) external;\n\n /// @notice Cancel the recovery of a payload.\n /// @param centrifugeId Chain where the adapter is configured for\n /// @param adapter Adapter that the recovery was targeting\n /// @param payloadHash Hash of the payload being disputed\n function disputeRecovery(uint16 centrifugeId, IAdapter adapter, bytes32 payloadHash) external;\n}\n\n/// -----------------------------------------------------\n/// CP Handlers\n/// -----------------------------------------------------\n\n/// @notice Interface for CP methods called by messages\ninterface IHubGatewayHandler {\n /// @notice Tells that an asset was already registered in CV, in order to perform the corresponding register.\n function registerAsset(AssetId assetId, uint8 decimals) external;\n\n /// @notice Perform a deposit that was requested from CV.\n function depositRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId depositAssetId, uint128 amount)\n external;\n\n /// @notice Perform a redeem that was requested from CV.\n function redeemRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId payoutAssetId, uint128 amount)\n external;\n\n /// @notice Perform a deposit cancellation that was requested from CV.\n function cancelDepositRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId depositAssetId)\n external;\n\n /// @notice Perform a redeem cancellation that was requested from CV.\n function cancelRedeemRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId payoutAssetId) external;\n\n /// @notice Update a holding by request from CAL.\n function updateHoldingAmount(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n uint128 amount,\n D18 pricePoolPerAsset,\n bool isIncrease\n ) external;\n\n /// @notice Increases the total issuance of shares by request from CAL.\n function increaseShareIssuance(PoolId poolId, ShareClassId scId, uint128 amount) external;\n\n /// @notice Decreases the total issuance of shares by request from CAL.\n function decreaseShareIssuance(PoolId poolId, ShareClassId scId, uint128 amount) external;\n}\n\n/// -----------------------------------------------------\n/// CV Handlers\n/// -----------------------------------------------------\n\n/// @notice Interface for CV methods related to pools called by messages\ninterface IPoolManagerGatewayHandler {\n /// @notice New pool details from an existing Centrifuge pool are added.\n /// @dev The function can only be executed by the gateway contract.\n function addPool(PoolId poolId) external;\n\n /// @notice New share class details from an existing Centrifuge pool are added.\n /// @dev The function can only be executed by the gateway contract.\n function addShareClass(\n PoolId poolId,\n ShareClassId scId,\n string memory tokenName,\n string memory tokenSymbol,\n uint8 decimals,\n bytes32 salt,\n address hook\n ) external;\n\n /// @notice Updates the tokenName and tokenSymbol of a share class token\n /// @dev The function can only be executed by the gateway contract.\n function updateShareMetadata(PoolId poolId, ShareClassId scId, string memory tokenName, string memory tokenSymbol)\n external;\n\n /// @notice Updates the price of a share class token, i.e. the factor of pool currency amount per share class token\n /// @dev The function can only be executed by the gateway contract.\n /// @param poolId The pool id\n /// @param scId The share class id\n /// @param price The price of pool currency per share class token as factor.\n /// @param computedAt The timestamp when the price was computed\n function updatePricePoolPerShare(PoolId poolId, ShareClassId scId, uint128 price, uint64 computedAt) external;\n\n /// @notice Updates the price of an asset, i.e. the factor of pool currency amount per asset unit\n /// @dev The function can only be executed by the gateway contract.\n /// @param poolId The pool id\n /// @param scId The share class id\n /// @param assetId The asset id\n /// @param poolPerAsset The price of pool currency per asset unit as factor.\n /// @param computedAt The timestamp when the price was computed\n function updatePricePoolPerAsset(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n uint128 poolPerAsset,\n uint64 computedAt\n ) external;\n\n /// @notice Updates the hook of a share class token\n /// @param poolId The centrifuge pool id\n /// @param scId The share class id\n /// @param hook The new hook addres\n function updateShareHook(PoolId poolId, ShareClassId scId, address hook) external;\n\n /// @notice Updates the restrictions on a share class token for a specific user\n /// @param poolId The centrifuge pool id\n /// @param scId The share class id\n /// @param update The restriction update in the form of a bytes array indicating\n /// the restriction to be updated, the user to be updated, and a validUntil timestamp.\n function updateRestriction(PoolId poolId, ShareClassId scId, bytes memory update) external;\n\n /// @notice Mints share class tokens to a recipient\n /// @dev The function can only be executed internally or by the gateway contract.\n function handleTransferShares(PoolId poolId, ShareClassId scId, address destinationAddress, uint128 amount)\n external;\n\n /// @notice Updates the target address. Generic update function from CP to CV\n /// @param poolId The centrifuge pool id\n /// @param scId The share class id\n /// @param target The target address to be called\n /// @param update The payload to be processed by the target address\n function updateContract(PoolId poolId, ShareClassId scId, address target, bytes memory update) external;\n}\n\n/// @notice Interface for CV methods related to async investments called by messages\ninterface IRequestManagerGatewayHandler {\n /// @notice Signal from the Hub that an asynchronous investment order has been approved\n ///\n /// @dev This message needs to trigger making the asset amounts available to the pool-share-class.\n function approvedDeposits(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n uint128 assetAmount,\n D18 pricePoolPerAsset\n ) external;\n\n /// @notice Signal from the Hub that an asynchronous investment order has been finalized. Shares have been issued.\n ///\n /// @dev This message needs to trigger minting the new amount of shares.\n function issuedShares(PoolId poolId, ShareClassId scId, uint128 shareAmount, D18 pricePoolPerShare) external;\n\n /// @notice Signal from the Hub that an asynchronous redeem order has been finalized.\n ///\n /// @dev This messages needs to trigger reserving the asset amount for claims of redemptions by users.\n function revokedShares(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n uint128 assetAmount,\n uint128 shareAmount,\n D18 pricePoolPerShare\n ) external;\n\n // --- Deposits ---\n /// @notice Fulfills pending deposit requests after successful epoch execution on CP.\n /// The amount of shares that can be claimed by the user is minted and moved to the escrow contract.\n /// The MaxMint bookkeeping value is updated.\n /// The request fulfillment can be partial.\n /// @dev The shares in the escrow are reserved for the user and are transferred to the user on deposit\n /// and mint calls.\n function fulfillDepositRequest(\n PoolId poolId,\n ShareClassId scId,\n address user,\n AssetId assetId,\n uint128 assets,\n uint128 shares\n ) external;\n\n /// @notice Fulfills deposit request cancellation after successful epoch execution on CP.\n /// The amount of assets that can be claimed by the user is locked in the escrow contract.\n /// Updates claimableCancelDepositRequest bookkeeping value. The cancellation order execution can be\n /// partial.\n /// @dev The assets in the escrow are reserved for the user and are transferred to the user during\n /// claimCancelDepositRequest calls.\n /// `fulfillment` represents the decrease in `pendingDepositRequest`.\n /// This is a separate parameter from `assets` since there can be some precision loss when calculating this,\n /// which would lead to having dust in the pendingDepositRequest value and\n /// never closing out the request even after it is technically fulfilled.\n ///\n /// Example:\n /// User deposits 100 units of the vaults underlying asset.\n /// - At some point they make cancellation request. The order in which is not guaranteed\n /// Both requests arrive at CentrifugeChain. If the cancellation is first then all of the\n /// deposited amount will be cancelled.\n ///\n /// - There is the case where the deposit event is first and it gets completely fulfilled then\n /// No amount of the deposited asset will be cancelled.\n ///\n /// - There is the case where partially the deposit request is fulfilled. Let's say 40 units.\n /// Then the cancel request arrives.\n /// The remaining amount of deposited funds which is 60 units will cancelled.\n /// There is a scenario where the deposit funds might different from the pool currency so some\n /// swapping might happen. Either during this swapping or some fee collection or rounding there will be\n /// difference between the actual amount that will be returned to the user.\n /// `fulfillment` in this case will be 60 units but assets will be some lower amount because of the\n /// aforementioned reasons\n /// Let's assume the `asset` is 59. The user will be able to take back these 59 but\n /// in order to not let any dust, we use `fulfillment` in our calculations.\n ///\n /// `pendingDepositRequest` not necessary gets zeroed during this cancellation event.\n /// When CentrifugeChain process the cancel event on its side, part of the deposit might be fulfilled.\n /// In such case the chain will send two messages, one `fulfillDepositRequest` and one\n /// `fulfillCancelDepositRequest`. In the example above, given the 100 units\n /// deposited, 40 units are fulfilled and 60 can be cancelled.\n /// The two messages sent from CentrifugeChain are not guaranteed to arrive in order.\n ///\n /// Assuming first is the `fulfillCancelDepositRequest` the `pendingDepositRequest` here will be reduced to\n /// 60 units only. Then the `fulfillCancelDepositRequest` arrives with `fulfillment` 60. This amount is\n /// removed from `pendingDepositRequests`. Since there are not more pendingDepositRequest` the\n /// `pendingCancelDepositRequest` gets deleted.\n ///\n /// Assuming first the `fulfillCancelDepositRequest` arrives then the `pendingDepositRequest` will be 100.\n /// `fulfillment` is 60 so we are left with `pendingDepositRequest` equals to 40 ( 100 - 60 ).\n /// Then the second message arrives which is `fulfillDepositRequest`. ( Check `fulfillDepositRequest`\n /// implementation for details.)\n /// When it arrives the `pendingDepositRequest` is 40 and the assets is 40\n /// so there are no more `pendingDepositRequest` and right there the `pendingCancelDepositRequest will be\n /// deleted.\n function fulfillCancelDepositRequest(\n PoolId poolId,\n ShareClassId scId,\n address user,\n AssetId assetId,\n uint128 assets,\n uint128 fulfillment\n ) external;\n\n // --- Redeems ---\n /// @notice Fulfills pending redeem requests after successful epoch execution on CP.\n /// The amount of redeemed shares is burned. The amount of assets that can be claimed by the user in\n /// return is locked in the escrow contract. The MaxWithdraw bookkeeping value is updated.\n /// The request fulfillment can be partial.\n /// @dev The assets in the escrow are reserved for the user and are transferred to the user on redeem\n /// and withdraw calls.\n function fulfillRedeemRequest(\n PoolId poolId,\n ShareClassId scId,\n address user,\n AssetId assetId,\n uint128 assets,\n uint128 shares\n ) external;\n\n /// @notice Fulfills redeem request cancellation after successful epoch execution on CP.\n /// The amount of shares that can be claimed by the user is locked in the escrow contract.\n /// Updates claimableCancelRedeemRequest bookkeeping value. The cancellation order execution can also be\n /// partial.\n /// @dev The shares in the escrow are reserved for the user and are transferred to the user during\n /// claimCancelRedeemRequest calls.\n function fulfillCancelRedeemRequest(PoolId poolId, ShareClassId scId, address user, AssetId assetId, uint128 shares)\n external;\n}\n\n/// @notice Interface for CV methods related to epoch called by messages\ninterface IBalanceSheetGatewayHandler {\n function triggerDeposit(PoolId poolId, ShareClassId scId, AssetId assetId, address provider, uint128 amount)\n external;\n\n function triggerWithdraw(PoolId poolId, ShareClassId scId, AssetId assetId, address receiver, uint128 amount)\n external;\n\n function triggerIssueShares(PoolId poolId, ShareClassId scId, address to, uint128 shares) external;\n\n function submitQueuedShares(PoolId poolId, ShareClassId scId) external;\n\n function submitQueuedAssets(PoolId poolId, ShareClassId scId, AssetId assetId) external;\n\n function setQueue(PoolId poolId, ShareClassId scId, bool enabled) external;\n}\n" + }, + "src/common/interfaces/IGatewaySenders.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {D18} from \"src/misc/types/D18.sol\";\n\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\n\ninterface ILocalCentrifugeId {\n function localCentrifugeId() external view returns (uint16);\n}\n\n/// @notice Interface for dispatch-only gateway\ninterface IRootMessageSender {\n /// @notice Creates and send the message\n function sendScheduleUpgrade(uint16 centrifugeId, bytes32 target) external;\n\n /// @notice Creates and send the message\n function sendCancelUpgrade(uint16 centrifugeId, bytes32 target) external;\n\n /// @notice Creates and send the message\n function sendRecoverTokens(\n uint16 centrifugeId,\n bytes32 target,\n bytes32 token,\n uint256 tokenId,\n bytes32 to,\n uint256 amount\n ) external;\n\n /// @notice Creates and send the message\n function sendInitiateRecovery(uint16 centrifugeId, uint16 adapterCentrifugeId, bytes32 adapter, bytes32 hash)\n external;\n\n /// @notice Creates and send the message\n function sendDisputeRecovery(uint16 centrifugeId, uint16 adapterCentrifugeId, bytes32 adapter, bytes32 hash)\n external;\n}\n\n/// @notice Interface for dispatch-only gateway\ninterface IPoolMessageSender is ILocalCentrifugeId {\n /// @notice Creates and send the message\n function sendNotifyPool(uint16 centrifugeId, PoolId poolId) external;\n\n /// @notice Creates and send the message\n function sendNotifyShareClass(\n uint16 centrifugeId,\n PoolId poolId,\n ShareClassId scId,\n string memory name,\n string memory symbol,\n uint8 decimals,\n bytes32 salt,\n bytes32 hook\n ) external;\n\n /// @notice Creates and send the message\n function sendNotifyShareMetadata(\n uint16 centrifugeId,\n PoolId poolId,\n ShareClassId scId,\n string memory name,\n string memory symbol\n ) external;\n\n /// @notice Creates and send the message\n function sendUpdateShareHook(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bytes32 hook) external;\n\n /// @notice Creates and send the message\n function sendNotifyPricePoolPerShare(uint16 chainId, PoolId poolId, ShareClassId scId, D18 pricePerShare)\n external;\n\n /// @notice Creates and send the message\n function sendNotifyPricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId, D18 pricePerShare)\n external;\n\n /// @notice Creates and send the message\n function sendFulfilledDepositRequest(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n bytes32 investor,\n uint128 assetAmount,\n uint128 shareAmount\n ) external;\n\n /// @notice Creates and send the message\n function sendFulfilledRedeemRequest(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n bytes32 investor,\n uint128 assetAmount,\n uint128 shareAmount\n ) external;\n\n /// @notice Creates and send the message\n function sendFulfilledCancelDepositRequest(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n bytes32 investor,\n uint128 cancelledAmount\n ) external;\n\n /// @notice Creates and send the message\n function sendFulfilledCancelRedeemRequest(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n bytes32 investor,\n uint128 cancelledShares\n ) external;\n\n /// @notice Creates and send the message\n function sendUpdateRestriction(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bytes calldata payload)\n external;\n\n /// @notice Creates and send the message\n function sendUpdateContract(\n uint16 centrifugeId,\n PoolId poolId,\n ShareClassId scId,\n bytes32 target,\n bytes calldata payload\n ) external;\n\n /// @notice Creates and send the message\n function sendApprovedDeposits(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n uint128 assetAmount,\n D18 pricePoolPerAsset\n ) external;\n\n // @notice Creates and send the message\n function sendIssuedShares(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n uint128 shareAmount,\n D18 pricePoolPerShare\n ) external;\n\n /// @notice Creates and send the message\n function sendRevokedShares(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n uint128 assetAmount,\n uint128 shareAmount,\n D18 pricePoolPerShare\n ) external;\n\n /// @notice Creates and send the message\n function sendTriggerIssueShares(uint16 centrifugeId, PoolId poolId, ShareClassId scId, address who, uint128 shares)\n external;\n\n /// @notice Creates and send the message\n function sendTriggerSubmitQueuedShares(uint16 centrifugeId, PoolId poolId, ShareClassId scId) external;\n\n /// @notice Creates and send the message\n function sendTriggerSubmitQueuedAssets(PoolId poolId, ShareClassId scId, AssetId assetId) external;\n\n /// @notice Creates and send the message\n function sendSetQueue(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bool enabled) external;\n}\n\n/// @notice Interface for dispatch-only gateway\ninterface IVaultMessageSender is ILocalCentrifugeId {\n /// @notice Creates and send the message\n function sendTransferShares(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bytes32 receiver, uint128 amount)\n external;\n\n /// @notice Creates and send the message\n function sendDepositRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId assetId, uint128 amount)\n external;\n\n /// @notice Creates and send the message\n function sendRedeemRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId assetId, uint128 amount)\n external;\n\n /// @notice Creates and send the message\n function sendCancelDepositRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId assetId) external;\n\n /// @notice Creates and send the message\n function sendCancelRedeemRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId assetId) external;\n\n /// @notice Creates and send the message\n function sendRegisterAsset(uint16 centrifugeId, AssetId assetId, uint8 decimals) external;\n\n /// @notice Creates and send the message\n function sendUpdateHoldingAmount(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n address provider,\n uint128 amount,\n D18 pricePoolPerAsset,\n bool isIncrease\n ) external;\n\n /// @notice Creates and send the message\n function sendUpdateShares(PoolId poolId, ShareClassId scId, uint128 shares, bool isIssuance) external;\n}\n" + }, + "src/common/interfaces/IGuardian.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {IAdapter} from \"src/common/interfaces/IAdapter.sol\";\n\ninterface ISafe {\n function isOwner(address signer) external view returns (bool);\n}\n\ninterface IGuardian {\n error NotTheAuthorizedSafe();\n error NotTheAuthorizedSafeOrItsOwner();\n\n /// @notice Dispatched when the `what` parameter of `file()` is not supported by the implementation.\n error FileUnrecognizedParam();\n\n /// @notice Emitted when a call to `file()` was performed.\n event File(bytes32 indexed what, address addr);\n\n /// @notice Return the linked Safe\n function safe() external view returns (ISafe);\n\n /// @notice Updates a contract parameter.\n /// @param what Name of the parameter to update.\n /// Accepts a `bytes32` representation of 'sender' string value.\n /// @param data New value given to the `what` parameter\n function file(bytes32 what, address data) external;\n\n /// @notice Registers a new pool\n function createPool(PoolId poolId, address admin, AssetId currency) external;\n\n /// @notice Pause the protocol\n /// @dev callable by both safe and owners\n function pause() external;\n\n /// @notice Unpause the protocol\n /// @dev callable by safe only\n function unpause() external;\n\n /// @notice Schedule relying a target address on Root\n /// @dev callable by safe only\n function scheduleRely(address target) external;\n\n /// @notice Cancel a scheduled rely\n /// @dev callable by safe only\n function cancelRely(address target) external;\n\n /// @notice Schedule an upgrade (scheduled rely) on a specific chain\n /// @dev Only supports EVM targets today\n function scheduleUpgrade(uint16 centrifugeId, address target) external;\n\n /// @notice Cancel an upgrade (scheduled rely) on a specific chain\n /// @dev Only supports EVM targets today\n function cancelUpgrade(uint16 centrifugeId, address target) external;\n\n /// @notice Recover tokens on a specific chain\n /// @dev Only supports EVM targets today\n function recoverTokens(\n uint16 centrifugeId,\n address target,\n address token,\n uint256 tokenId,\n address to,\n uint256 amount\n ) external;\n\n /// @notice Initiate a gateway payload recovery on a specific chain\n /// @dev Only supports EVM targets today\n function initiateRecovery(uint16 centrifugeId, uint16 adapterCentrifugeId, IAdapter adapter, bytes32 hash)\n external;\n\n /// @notice Dispute a gateway paylaod recovery on a specific chain\n /// @dev Only supports EVM targets today\n function disputeRecovery(uint16 centrifugeId, uint16 adapterCentrifugeId, IAdapter adapter, bytes32 hash)\n external;\n}\n" + }, + "src/common/interfaces/IGuardianActions.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\n\ninterface IHubGuardianActions {\n /// @notice Creates a new pool. `msg.sender` will be the admin of the created pool.\n /// @param currency The pool currency. Usually an AssetId identifying by a ISO4217 code.\n function createPool(PoolId poolId, address admin, AssetId currency) external payable;\n}\n" + }, + "src/common/interfaces/IHook.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IERC165} from \"src/misc/interfaces/IERC7575.sol\";\n\nstruct HookData {\n bytes16 from;\n bytes16 to;\n}\n\nuint8 constant SUCCESS_CODE_ID = 0;\nstring constant SUCCESS_MESSAGE = \"transfer-allowed\";\n\nuint8 constant ERROR_CODE_ID = 1;\nstring constant ERROR_MESSAGE = \"transfer-blocked\";\n\n/// @dev Magic address denoting a transfer to the escrow\n/// @dev Solely used for gas saving since escrow is per pool\naddress constant ESCROW_HOOK_ID = address(uint160(uint8(0xce)));\n\n/// @notice Hook interface to customize share token behaviour\n/// @dev To detect specific system actions:\n/// Deposit request: address(0) -> address(user)\n/// Deposit claim: ESCROW_HOOK_ID -> address(user)\n/// Redeem request: address(user) -> ESCROW_HOOK_ID\n/// Redeem claim: address(user) -> address(0)\n/// Cross-chain transfer: address(user) -> address(uint160(chainId))\ninterface IHook is IERC165 {\n // --- Errors ---\n error TransferBlocked();\n error InvalidUpdate();\n\n /// @notice Callback on standard ERC20 transfer.\n /// @dev MUST return bytes4(keccak256(\"onERC20Transfer(address,address,uint256,(bytes16,bytes16))\"))\n /// if successful\n function onERC20Transfer(address from, address to, uint256 value, HookData calldata hookdata)\n external\n returns (bytes4);\n\n /// @notice Callback on authorized ERC20 transfer.\n /// @dev Cannot be blocked, can only be used to update state.\n /// Return value is ignored, only kept for compatibility with V2 share tokens.\n function onERC20AuthTransfer(address sender, address from, address to, uint256 value, HookData calldata hookdata)\n external\n returns (bytes4);\n\n /// @notice Check if given transfer can be performed\n function checkERC20Transfer(address from, address to, uint256 value, HookData calldata hookData)\n external\n view\n returns (bool);\n\n /// @notice Update a set of restriction for a token\n /// @dev MAY be user specific, which would be included in the encoded `update` value\n function updateRestriction(address token, bytes memory update) external;\n}\n" + }, + "src/common/interfaces/IMessageDispatcher.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IVaultMessageSender, IPoolMessageSender, IRootMessageSender} from \"src/common/interfaces/IGatewaySenders.sol\";\n\ninterface IMessageDispatcher is IRootMessageSender, IVaultMessageSender, IPoolMessageSender {\n /// @notice Emitted when a call to `file()` was performed.\n event File(bytes32 indexed what, address addr);\n\n /// @notice Dispatched when the `what` parameter of `file()` is not supported by the implementation.\n error FileUnrecognizedParam();\n\n /// @notice Updates a contract parameter.\n /// @param what Name of the parameter to update.\n /// Accepts a `bytes32` representation of 'hubRegistry' string value.\n /// @param data New value given to the `what` parameter\n function file(bytes32 what, address data) external;\n\n /// @notice Estimate sending a message through the gateway.\n /// If the message is to the same centrifugeId, then the estimation is 0.\n function estimate(uint16 centrifugeId, bytes calldata payload) external view returns (uint256 amount);\n}\n" + }, + "src/common/interfaces/IMessageHandler.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\n/// @notice Generic interface for entities that handle incoming messages\ninterface IMessageHandler {\n /// @notice Dispatched when an invalid message is trying to handle\n error InvalidMessage(uint8 code);\n\n /// @notice Handling incoming messages.\n /// @param centrifugeId Source chain\n /// @param message Incoming message\n function handle(uint16 centrifugeId, bytes calldata message) external;\n}\n" + }, + "src/common/interfaces/IMessageProcessor.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IMessageHandler} from \"src/common/interfaces/IMessageHandler.sol\";\nimport {IMessageProperties} from \"src/common/interfaces/IMessageProperties.sol\";\n\ninterface IMessageProcessor is IMessageHandler, IMessageProperties {\n /// @notice Emitted when a call to `file()` was performed.\n event File(bytes32 indexed what, address addr);\n\n /// @notice Dispatched when the `what` parameter of `file()` is not supported by the implementation.\n error FileUnrecognizedParam();\n\n /// @notice Updates a contract parameter.\n /// @param what Name of the parameter to update.\n /// Accepts a `bytes32` representation of 'hubRegistry' string value.\n /// @param data New value given to the `what` parameter\n function file(bytes32 what, address data) external;\n}\n" + }, + "src/common/interfaces/IMessageProperties.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\n\n/// @notice Defines methods to get properties from raw messages\ninterface IMessageProperties {\n /// @notice Inspect the message to tell if the message is recovery message\n function isMessageRecovery(bytes calldata message) external pure returns (bool);\n\n /// @notice Inspect the message to return the length\n function messageLength(bytes calldata message) external pure returns (uint16);\n\n /// @notice Inspect the message to return the associated PoolId if any\n function messagePoolId(bytes calldata message) external pure returns (PoolId);\n}\n" + }, + "src/common/interfaces/IMessageSender.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\n/// @notice Generic interface for entities that handles outgoing messages\ninterface IMessageSender {\n /// @notice Handling outgoing messages.\n /// @param centrifugeId Destination chain\n function send(uint16 centrifugeId, bytes calldata message) external;\n}\n" + }, + "src/common/interfaces/IRoot.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IMessageHandler} from \"src/common/interfaces/IMessageHandler.sol\";\n\ninterface IRoot {\n // --- Events ---\n event File(bytes32 indexed what, uint256 data);\n event Pause();\n event Unpause();\n event ScheduleRely(address indexed target, uint256 indexed scheduledTime);\n event CancelRely(address indexed target);\n event RelyContract(address indexed target, address indexed user);\n event DenyContract(address indexed target, address indexed user);\n event Endorse(address indexed user);\n event Veto(address indexed user);\n\n error DelayTooLong();\n error FileUnrecognizedParam();\n error TargetNotScheduled();\n error TargetNotReady();\n\n /// @notice Returns whether the root is paused\n function paused() external view returns (bool);\n\n /// @notice Returns the current timelock for adding new wards\n function delay() external view returns (uint256);\n\n /// @notice Trusted contracts within the system\n function endorsements(address target) external view returns (uint256);\n\n /// @notice Returns when `relyTarget` has passed the timelock\n function schedule(address relyTarget) external view returns (uint256 timestamp);\n\n // --- Administration ---\n /// @notice Updates a contract parameter\n /// @param what Accepts a bytes32 representation of 'delay'\n function file(bytes32 what, uint256 data) external;\n\n /// --- Endorsements ---\n /// @notice Endorses the `user`\n /// @dev Endorsed users are trusted contracts in the system. They are allowed to bypass\n /// token restrictions (e.g. the Escrow can automatically receive share class tokens by being endorsed), and\n /// can automatically set operators in ERC-7540 vaults (e.g. the VaultRouter) is always an operator.\n function endorse(address user) external;\n\n /// @notice Removes the endorsed user\n function veto(address user) external;\n\n /// @notice Returns whether the user is endorsed\n function endorsed(address user) external view returns (bool);\n\n // --- Pause management ---\n /// @notice Pause any contracts that depend on `Root.paused()`\n function pause() external;\n\n /// @notice Unpause any contracts that depend on `Root.paused()`\n function unpause() external;\n\n /// --- Timelocked ward management ---\n /// @notice Schedule relying a new ward after the delay has passed\n function scheduleRely(address target) external;\n\n /// @notice Cancel a pending scheduled rely\n function cancelRely(address target) external;\n\n /// @notice Execute a scheduled rely\n /// @dev Can be triggered by anyone since the scheduling is protected\n function executeScheduledRely(address target) external;\n\n /// --- External contract ward management ---\n /// @notice Make an address a ward on any contract that Root is a ward on\n function relyContract(address target, address user) external;\n\n /// @notice Removes an address as a ward on any contract that Root is a ward on\n function denyContract(address target, address user) external;\n}\n" + }, + "src/common/interfaces/ITokenRecoverer.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IRecoverable} from \"src/misc/interfaces/IRecoverable.sol\";\n\ninterface ITokenRecoverer {\n event RecoverTokens(\n IRecoverable indexed target, address indexed token, uint256 tokenId, address indexed to, uint256 amount\n );\n\n function recoverTokens(IRecoverable target, address token, uint256 tokenId, address to, uint256 amount) external;\n}\n" + }, + "src/common/interfaces/IWormholeAdapter.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IAdapter} from \"src/common/interfaces/IAdapter.sol\";\n\n// From https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/interfaces/IWormholeRelayer.sol#L75\ninterface IWormholeRelayer {\n /**\n * @notice Publishes an instruction for the default delivery provider\n * to relay a payload to the address `targetAddress` on chain `targetChain`\n * with gas limit `gasLimit` and `msg.value` equal to `receiverValue`\n *\n * Any refunds (from leftover gas) will be sent to `refundAddress` on chain `refundChain`\n * `targetAddress` must implement the IWormholeReceiver interface\n *\n * This function must be called with `msg.value` equal to `quoteEVMDeliveryPrice(targetChain, receiverValue,\n * gasLimit)`\n *\n * @param targetChain in Wormhole Chain ID format\n * @param targetAddress address to call on targetChain (that implements IWormholeReceiver)\n * @param payload arbitrary bytes to pass in as parameter in call to `targetAddress`\n * @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain\n * currency units)\n * @param gasLimit gas limit with which to call `targetAddress`. Any units of gas unused will be refunded according\n * to the\n * `targetChainRefundPerGasUnused` rate quoted by the delivery provider\n * @param refundChain The chain to deliver any refund to, in Wormhole Chain ID format\n * @param refundAddress The address on `refundChain` to deliver any refund to\n * @return sequence sequence number of published VAA containing delivery instructions\n */\n function sendPayloadToEvm(\n uint16 targetChain,\n address targetAddress,\n bytes memory payload,\n uint256 receiverValue,\n uint256 gasLimit,\n uint16 refundChain,\n address refundAddress\n ) external payable returns (uint64 sequence);\n\n /**\n * @notice Returns the price to request a relay to chain `targetChain`, using the default delivery provider\n *\n * @param targetChain in Wormhole Chain ID format\n * @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain\n * currency units)\n * @param gasLimit gas limit with which to call `targetAddress`.\n * @return nativePriceQuote Price, in units of current chain currency, that the delivery provider charges to perform\n * the relay\n * @return targetChainRefundPerGasUnused amount of target chain currency that will be refunded per unit of gas\n * unused,\n * if a refundAddress is specified.\n * Note: This value can be overridden by the delivery provider on the target chain. The returned value here\n * should be considered to be a\n * promise by the delivery provider of the amount of refund per gas unused that will be returned to the\n * refundAddress at the target chain.\n * If a delivery provider decides to override, this will be visible as part of the emitted Delivery event on\n * the target chain.\n */\n function quoteEVMDeliveryPrice(uint16 targetChain, uint256 receiverValue, uint256 gasLimit)\n external\n view\n returns (uint256 nativePriceQuote, uint256 targetChainRefundPerGasUnused);\n\n /**\n * @notice Returns the address of the current default delivery provider\n * @return deliveryProvider The address of (the default delivery provider)'s contract on this source\n * chain. This must be a contract that implements IDeliveryProvider.\n */\n function getDefaultDeliveryProvider() external view returns (address deliveryProvider);\n}\n\ninterface IWormholeDeliveryProvider {\n /// @notice Returns the chain ID.\n function chainId() external view returns (uint16);\n}\n\n// From\n// https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IWormholeReceiver.sol\ninterface IWormholeReceiver {\n /**\n * @notice When a `send` is performed with this contract as the target, this function will be\n * invoked by the WormholeRelayer contract\n *\n * NOTE: This function should be restricted such that only the Wormhole Relayer contract can call it.\n *\n * We also recommend that this function checks that `sourceChain` and `sourceAddress` are indeed who\n * you expect to have requested the calling of `send` on the source chain\n *\n * The invocation of this function corresponding to the `send` request will have msg.value equal\n * to the receiverValue specified in the send request.\n *\n * If the invocation of this function reverts or exceeds the gas limit\n * specified by the send requester, this delivery will result in a `ReceiverFailure`.\n *\n * @param payload - an arbitrary message which was included in the delivery by the\n * requester. This message's signature will already have been verified (as long as msg.sender is the Wormhole\n * Relayer contract)\n * @param additionalMessages - Additional messages which were requested to be included in this delivery.\n * Note: There are no contract-level guarantees that the messages in this array are what was requested\n * so **you should verify any sensitive information given here!**\n *\n * For example, if a 'VaaKey' was specified on the source chain, then MAKE SURE the corresponding message here\n * has valid signatures (by calling `parseAndVerifyVM(message)` on the Wormhole core contract)\n *\n * This field can be used to perform and relay TokenBridge or CCTP transfers, and there are example\n * usages of this at\n * https://github.com/wormhole-foundation/hello-token\n * https://github.com/wormhole-foundation/hello-cctp\n *\n * @param sourceAddress - the (wormhole format) address on the sending chain which requested\n * this delivery.\n * @param sourceChain - the wormhole chain ID where this delivery was requested.\n * @param deliveryHash - the VAA hash of the deliveryVAA.\n *\n */\n function receiveWormholeMessages(\n bytes memory payload,\n bytes[] memory additionalMessages,\n bytes32 sourceAddress,\n uint16 sourceChain,\n bytes32 deliveryHash\n ) external payable;\n}\n\nstruct WormholeSource {\n uint16 centrifugeId;\n address addr;\n}\n\nstruct WormholeDestination {\n uint16 wormholeId;\n address addr;\n}\n\ninterface IWormholeAdapter is IAdapter, IWormholeReceiver {\n /// @dev see file() method\n event File(bytes32 indexed what, uint16 fromChainId, uint16 toChainId, address addr);\n\n error FileUnrecognizedParam();\n error NotWormholeRelayer();\n error InvalidSource();\n\n /// @dev Configures the adapter\n /// @param what Can be \"sources\" or \"destinations\".\n /// @param addr if what == \"sources\", it represents the source\n /// @param addr if what == \"destinations\", it represents the destination\n function file(bytes32 what, uint16 centrifugeId, uint16 wormholeId, address addr) external;\n}\n" + }, + "src/common/libraries/MessageLib.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\n\nenum MessageType {\n /// @dev Placeholder for null message type\n _Invalid,\n /// @dev Placeholder for proof message type\n _MessageProof,\n // -- Gateway messages\n InitiateRecovery,\n DisputeRecovery,\n // -- Root messages\n ScheduleUpgrade,\n CancelUpgrade,\n RecoverTokens,\n // -- Pool manager messages\n RegisterAsset,\n NotifyPool,\n NotifyShareClass,\n NotifyPricePoolPerShare,\n NotifyPricePoolPerAsset,\n NotifyShareMetadata,\n UpdateShareHook,\n TransferShares,\n UpdateRestriction,\n UpdateContract,\n ApprovedDeposits,\n IssuedShares,\n RevokedShares,\n // -- Investment manager messages\n DepositRequest,\n RedeemRequest,\n FulfilledDepositRequest,\n FulfilledRedeemRequest,\n CancelDepositRequest,\n CancelRedeemRequest,\n FulfilledCancelDepositRequest,\n FulfilledCancelRedeemRequest,\n // -- BalanceSheet messages\n UpdateHoldingAmount,\n UpdateShares,\n TriggerIssueShares,\n TriggerSubmitQueuedShares,\n TriggerSubmitQueuedAssets,\n SetQueue\n}\n\nenum UpdateRestrictionType {\n /// @dev Placeholder for null update restriction type\n Invalid,\n Member,\n Freeze,\n Unfreeze\n}\n\nenum UpdateContractType {\n /// @dev Placeholder for null update restriction type\n Invalid,\n VaultUpdate,\n UpdateManager,\n MaxAssetPriceAge,\n MaxSharePriceAge,\n Valuation,\n SyncDepositMaxReserve\n}\n\n/// @dev Used internally in the VaultUpdateMessage (not represent a submessage)\nenum VaultUpdateKind {\n DeployAndLink,\n Link,\n Unlink\n}\n\nlibrary MessageLib {\n using MessageLib for bytes;\n using BytesLib for bytes;\n using CastLib for *;\n\n error UnknownMessageType();\n\n /// @dev Encode all message lengths in this constant to avoid a large list of if/elseif checks\n /// and reduce generated bytecode.\n /// If the message has some dynamic part, will be added later in `messageLength()`.\n // forgefmt: disable-next-item\n uint256 constant MESSAGE_LENGTHS_1 =\n (67 << uint8(MessageType.InitiateRecovery) * 8) +\n (67 << uint8(MessageType.DisputeRecovery) * 8) +\n (33 << uint8(MessageType.ScheduleUpgrade) * 8) +\n (33 << uint8(MessageType.CancelUpgrade) * 8) +\n (161 << uint8(MessageType.RecoverTokens) * 8) +\n (18 << uint8(MessageType.RegisterAsset) * 8) +\n (9 << uint8(MessageType.NotifyPool) * 8) +\n (250 << uint8(MessageType.NotifyShareClass) * 8) +\n (49 << uint8(MessageType.NotifyPricePoolPerShare) * 8) +\n (65 << uint8(MessageType.NotifyPricePoolPerAsset) * 8) +\n (185 << uint8(MessageType.NotifyShareMetadata) * 8) +\n (57 << uint8(MessageType.UpdateShareHook) * 8) +\n (73 << uint8(MessageType.TransferShares) * 8) +\n (25 << uint8(MessageType.UpdateRestriction) * 8) +\n (57 << uint8(MessageType.UpdateContract) * 8) +\n (73 << uint8(MessageType.ApprovedDeposits) * 8) +\n (57 << uint8(MessageType.IssuedShares) * 8) +\n (89 << uint8(MessageType.RevokedShares) * 8) +\n (89 << uint8(MessageType.DepositRequest) * 8) +\n (89 << uint8(MessageType.RedeemRequest) * 8) +\n (105 << uint8(MessageType.FulfilledDepositRequest) * 8) +\n (105 << uint8(MessageType.FulfilledRedeemRequest) * 8) +\n (73 << uint8(MessageType.CancelDepositRequest) * 8) +\n (73 << uint8(MessageType.CancelRedeemRequest) * 8) +\n (89 << uint8(MessageType.FulfilledCancelDepositRequest) * 8) +\n (89 << uint8(MessageType.FulfilledCancelRedeemRequest) * 8) +\n (114 << uint8(MessageType.UpdateHoldingAmount) * 8) +\n (50 << uint8(MessageType.UpdateShares) * 8) +\n (73 << uint8(MessageType.TriggerIssueShares) * 8) +\n (25 << uint8(MessageType.TriggerSubmitQueuedShares) * 8);\n\n // forgefmt: disable-next-item\n uint256 constant MESSAGE_LENGTHS_2 =\n (41 << (uint8(MessageType.TriggerSubmitQueuedAssets) - 32) * 8) +\n (26 << (uint8(MessageType.SetQueue) - 32) * 8);\n\n function messageType(bytes memory message) internal pure returns (MessageType) {\n return MessageType(message.toUint8(0));\n }\n\n function messageCode(bytes memory message) internal pure returns (uint8) {\n return message.toUint8(0);\n }\n\n function messageLength(bytes memory message) internal pure returns (uint16 length) {\n uint8 kind = message.toUint8(0);\n require(kind <= uint8(type(MessageType).max), UnknownMessageType());\n\n length = (kind <= 31)\n ? uint16(uint8(bytes32(MESSAGE_LENGTHS_1)[31 - kind]))\n : uint16(uint8(bytes32(MESSAGE_LENGTHS_2)[63 - kind]));\n\n // Spetial treatment for messages with dynamic size:\n if (kind == uint8(MessageType.UpdateRestriction)) {\n length += 2 + message.toUint16(length); //payloadLength\n } else if (kind == uint8(MessageType.UpdateContract)) {\n length += 2 + message.toUint16(length); //payloadLength\n }\n }\n\n function messagePoolId(bytes memory message) internal pure returns (PoolId poolId) {\n uint8 kind = message.toUint8(0);\n\n // All messages from NotifyPool to SetQueue contains a PoolId in position 1.\n if (kind >= uint8(MessageType.NotifyPool) && kind <= uint8(MessageType.SetQueue)) {\n return PoolId.wrap(message.toUint64(1));\n } else {\n return PoolId.wrap(0);\n }\n }\n\n function updateRestrictionType(bytes memory message) internal pure returns (UpdateRestrictionType) {\n return UpdateRestrictionType(message.toUint8(0));\n }\n\n function updateContractType(bytes memory message) internal pure returns (UpdateContractType) {\n return UpdateContractType(message.toUint8(0));\n }\n\n //---------------------------------------\n // InitiateRecovery\n //---------------------------------------\n\n struct InitiateRecovery {\n bytes32 hash;\n bytes32 adapter;\n uint16 centrifugeId;\n }\n\n function deserializeInitiateRecovery(bytes memory data) internal pure returns (InitiateRecovery memory) {\n require(messageType(data) == MessageType.InitiateRecovery, UnknownMessageType());\n return InitiateRecovery({hash: data.toBytes32(1), adapter: data.toBytes32(33), centrifugeId: data.toUint16(65)});\n }\n\n function serialize(InitiateRecovery memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.InitiateRecovery, t.hash, t.adapter, t.centrifugeId);\n }\n\n //---------------------------------------\n // DisputeRecovery\n //---------------------------------------\n\n struct DisputeRecovery {\n bytes32 hash;\n bytes32 adapter;\n uint16 centrifugeId;\n }\n\n function deserializeDisputeRecovery(bytes memory data) internal pure returns (DisputeRecovery memory) {\n require(messageType(data) == MessageType.DisputeRecovery, UnknownMessageType());\n return DisputeRecovery({hash: data.toBytes32(1), adapter: data.toBytes32(33), centrifugeId: data.toUint16(65)});\n }\n\n function serialize(DisputeRecovery memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.DisputeRecovery, t.hash, t.adapter, t.centrifugeId);\n }\n\n //---------------------------------------\n // ScheduleUpgrade\n //---------------------------------------\n\n struct ScheduleUpgrade {\n bytes32 target;\n }\n\n function deserializeScheduleUpgrade(bytes memory data) internal pure returns (ScheduleUpgrade memory) {\n require(messageType(data) == MessageType.ScheduleUpgrade, UnknownMessageType());\n return ScheduleUpgrade({target: data.toBytes32(1)});\n }\n\n function serialize(ScheduleUpgrade memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.ScheduleUpgrade, t.target);\n }\n\n //---------------------------------------\n // CancelUpgrade\n //---------------------------------------\n\n struct CancelUpgrade {\n bytes32 target;\n }\n\n function deserializeCancelUpgrade(bytes memory data) internal pure returns (CancelUpgrade memory) {\n require(messageType(data) == MessageType.CancelUpgrade, UnknownMessageType());\n return CancelUpgrade({target: data.toBytes32(1)});\n }\n\n function serialize(CancelUpgrade memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.CancelUpgrade, t.target);\n }\n\n //---------------------------------------\n // RecoverTokens\n //---------------------------------------\n\n struct RecoverTokens {\n bytes32 target;\n bytes32 token;\n uint256 tokenId;\n bytes32 to;\n uint256 amount;\n }\n\n function deserializeRecoverTokens(bytes memory data) internal pure returns (RecoverTokens memory) {\n require(messageType(data) == MessageType.RecoverTokens, UnknownMessageType());\n return RecoverTokens({\n target: data.toBytes32(1),\n token: data.toBytes32(33),\n tokenId: data.toUint256(65),\n to: data.toBytes32(97),\n amount: data.toUint256(129)\n });\n }\n\n function serialize(RecoverTokens memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.RecoverTokens, t.target, t.token, t.tokenId, t.to, t.amount);\n }\n\n //---------------------------------------\n // RegisterAsset\n //---------------------------------------\n\n struct RegisterAsset {\n uint128 assetId;\n uint8 decimals;\n }\n\n function deserializeRegisterAsset(bytes memory data) internal pure returns (RegisterAsset memory) {\n require(messageType(data) == MessageType.RegisterAsset, UnknownMessageType());\n return RegisterAsset({assetId: data.toUint128(1), decimals: data.toUint8(17)});\n }\n\n function serialize(RegisterAsset memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.RegisterAsset, t.assetId, t.decimals);\n }\n\n //---------------------------------------\n // NotifyPool\n //---------------------------------------\n\n struct NotifyPool {\n uint64 poolId;\n }\n\n function deserializeNotifyPool(bytes memory data) internal pure returns (NotifyPool memory) {\n require(messageType(data) == MessageType.NotifyPool, UnknownMessageType());\n return NotifyPool({poolId: data.toUint64(1)});\n }\n\n function serialize(NotifyPool memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.NotifyPool, t.poolId);\n }\n\n //---------------------------------------\n // NotifyShareClass\n //---------------------------------------\n\n struct NotifyShareClass {\n uint64 poolId;\n bytes16 scId;\n string name; // Fixed to 128 bytes\n bytes32 symbol; // utf8\n uint8 decimals;\n bytes32 salt;\n bytes32 hook;\n }\n\n function deserializeNotifyShareClass(bytes memory data) internal pure returns (NotifyShareClass memory) {\n require(messageType(data) == MessageType.NotifyShareClass, UnknownMessageType());\n return NotifyShareClass({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n name: data.slice(25, 128).bytes128ToString(),\n symbol: data.toBytes32(153),\n decimals: data.toUint8(185),\n salt: data.toBytes32(186),\n hook: data.toBytes32(218)\n });\n }\n\n function serialize(NotifyShareClass memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(\n MessageType.NotifyShareClass,\n t.poolId,\n t.scId,\n bytes(t.name).sliceZeroPadded(0, 128),\n t.symbol,\n t.decimals,\n t.salt,\n t.hook\n );\n }\n\n //---------------------------------------\n // NotifyPricePoolPerShare\n //---------------------------------------\n\n struct NotifyPricePoolPerShare {\n uint64 poolId;\n bytes16 scId;\n uint128 price;\n uint64 timestamp;\n }\n\n function deserializeNotifyPricePoolPerShare(bytes memory data)\n internal\n pure\n returns (NotifyPricePoolPerShare memory)\n {\n require(messageType(data) == MessageType.NotifyPricePoolPerShare, UnknownMessageType());\n return NotifyPricePoolPerShare({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n price: data.toUint128(25),\n timestamp: data.toUint64(41)\n });\n }\n\n function serialize(NotifyPricePoolPerShare memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.NotifyPricePoolPerShare, t.poolId, t.scId, t.price, t.timestamp);\n }\n\n //---------------------------------------\n // NotifyPricePoolPerAsset\n //---------------------------------------\n\n struct NotifyPricePoolPerAsset {\n uint64 poolId;\n bytes16 scId;\n uint128 assetId;\n uint128 price;\n uint64 timestamp;\n }\n\n function deserializeNotifyPricePoolPerAsset(bytes memory data)\n internal\n pure\n returns (NotifyPricePoolPerAsset memory)\n {\n require(messageType(data) == MessageType.NotifyPricePoolPerAsset, UnknownMessageType());\n return NotifyPricePoolPerAsset({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n assetId: data.toUint128(25),\n price: data.toUint128(41),\n timestamp: data.toUint64(57)\n });\n }\n\n function serialize(NotifyPricePoolPerAsset memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.NotifyPricePoolPerAsset, t.poolId, t.scId, t.assetId, t.price, t.timestamp);\n }\n\n //---------------------------------------\n // NotifyShareMetadata\n //---------------------------------------\n\n struct NotifyShareMetadata {\n uint64 poolId;\n bytes16 scId;\n string name; // Fixed to 128 bytes\n bytes32 symbol; // utf8\n }\n\n function deserializeNotifyShareMetadata(bytes memory data) internal pure returns (NotifyShareMetadata memory) {\n require(messageType(data) == MessageType.NotifyShareMetadata, UnknownMessageType());\n return NotifyShareMetadata({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n name: data.slice(25, 128).bytes128ToString(),\n symbol: data.toBytes32(153)\n });\n }\n\n function serialize(NotifyShareMetadata memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(\n MessageType.NotifyShareMetadata, t.poolId, t.scId, bytes(t.name).sliceZeroPadded(0, 128), t.symbol\n );\n }\n\n //---------------------------------------\n // UpdateShareHook\n //---------------------------------------\n\n struct UpdateShareHook {\n uint64 poolId;\n bytes16 scId;\n bytes32 hook;\n }\n\n function deserializeUpdateShareHook(bytes memory data) internal pure returns (UpdateShareHook memory) {\n require(messageType(data) == MessageType.UpdateShareHook, UnknownMessageType());\n return UpdateShareHook({poolId: data.toUint64(1), scId: data.toBytes16(9), hook: data.toBytes32(25)});\n }\n\n function serialize(UpdateShareHook memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.UpdateShareHook, t.poolId, t.scId, t.hook);\n }\n\n //---------------------------------------\n // TransferShares\n //---------------------------------------\n\n struct TransferShares {\n uint64 poolId;\n bytes16 scId;\n bytes32 receiver;\n uint128 amount;\n }\n\n function deserializeTransferShares(bytes memory data) internal pure returns (TransferShares memory) {\n require(messageType(data) == MessageType.TransferShares, UnknownMessageType());\n return TransferShares({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n receiver: data.toBytes32(25),\n amount: data.toUint128(57)\n });\n }\n\n function serialize(TransferShares memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.TransferShares, t.poolId, t.scId, t.receiver, t.amount);\n }\n\n //---------------------------------------\n // UpdateRestriction\n //---------------------------------------\n\n struct UpdateRestriction {\n uint64 poolId;\n bytes16 scId;\n bytes payload; // As sequence of bytes\n }\n\n function deserializeUpdateRestriction(bytes memory data) internal pure returns (UpdateRestriction memory) {\n require(messageType(data) == MessageType.UpdateRestriction, UnknownMessageType());\n\n uint16 payloadLength = data.toUint16(25);\n return UpdateRestriction({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n payload: data.slice(27, payloadLength)\n });\n }\n\n function serialize(UpdateRestriction memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.UpdateRestriction, t.poolId, t.scId, uint16(t.payload.length), t.payload);\n }\n\n //---------------------------------------\n // UpdateRestrictionMember (submsg)\n //---------------------------------------\n\n struct UpdateRestrictionMember {\n bytes32 user;\n uint64 validUntil;\n }\n\n function deserializeUpdateRestrictionMember(bytes memory data)\n internal\n pure\n returns (UpdateRestrictionMember memory)\n {\n require(updateRestrictionType(data) == UpdateRestrictionType.Member, UnknownMessageType());\n\n return UpdateRestrictionMember({user: data.toBytes32(1), validUntil: data.toUint64(33)});\n }\n\n function serialize(UpdateRestrictionMember memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(UpdateRestrictionType.Member, t.user, t.validUntil);\n }\n\n //---------------------------------------\n // UpdateRestrictionFreeze (submsg)\n //---------------------------------------\n\n struct UpdateRestrictionFreeze {\n bytes32 user;\n }\n\n function deserializeUpdateRestrictionFreeze(bytes memory data)\n internal\n pure\n returns (UpdateRestrictionFreeze memory)\n {\n require(updateRestrictionType(data) == UpdateRestrictionType.Freeze, UnknownMessageType());\n\n return UpdateRestrictionFreeze({user: data.toBytes32(1)});\n }\n\n function serialize(UpdateRestrictionFreeze memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(UpdateRestrictionType.Freeze, t.user);\n }\n\n //---------------------------------------\n // UpdateRestrictionUnfreeze (submsg)\n //---------------------------------------\n\n struct UpdateRestrictionUnfreeze {\n bytes32 user;\n }\n\n function deserializeUpdateRestrictionUnfreeze(bytes memory data)\n internal\n pure\n returns (UpdateRestrictionUnfreeze memory)\n {\n require(updateRestrictionType(data) == UpdateRestrictionType.Unfreeze, UnknownMessageType());\n\n return UpdateRestrictionUnfreeze({user: data.toBytes32(1)});\n }\n\n function serialize(UpdateRestrictionUnfreeze memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(UpdateRestrictionType.Unfreeze, t.user);\n }\n\n //---------------------------------------\n // UpdateContract\n //---------------------------------------\n\n struct UpdateContract {\n uint64 poolId;\n bytes16 scId;\n bytes32 target;\n bytes payload; // As sequence of bytes\n }\n\n function deserializeUpdateContract(bytes memory data) internal pure returns (UpdateContract memory) {\n require(messageType(data) == MessageType.UpdateContract, UnknownMessageType());\n uint16 payloadLength = data.toUint16(57);\n return UpdateContract({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n target: data.toBytes32(25),\n payload: data.slice(59, payloadLength)\n });\n }\n\n function serialize(UpdateContract memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(\n MessageType.UpdateContract, t.poolId, t.scId, t.target, uint16(t.payload.length), t.payload\n );\n }\n\n //---------------------------------------\n // UpdateContract.VaultUpdate (submsg)\n //---------------------------------------\n\n struct UpdateContractVaultUpdate {\n bytes32 vaultOrFactory;\n uint128 assetId;\n uint8 kind;\n }\n\n function deserializeUpdateContractVaultUpdate(bytes memory data)\n internal\n pure\n returns (UpdateContractVaultUpdate memory)\n {\n require(updateContractType(data) == UpdateContractType.VaultUpdate, UnknownMessageType());\n\n return UpdateContractVaultUpdate({\n vaultOrFactory: data.toBytes32(1),\n assetId: data.toUint128(33),\n kind: data.toUint8(49)\n });\n }\n\n function serialize(UpdateContractVaultUpdate memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(UpdateContractType.VaultUpdate, t.vaultOrFactory, t.assetId, t.kind);\n }\n\n //---------------------------------------\n // UpdateContract.UpdateManager (submsg)\n //---------------------------------------\n\n struct UpdateContractUpdateManager {\n bytes32 who;\n bool canManage;\n }\n\n function deserializeUpdateContractUpdateManager(bytes memory data)\n internal\n pure\n returns (UpdateContractUpdateManager memory)\n {\n require(updateContractType(data) == UpdateContractType.UpdateManager, UnknownMessageType());\n\n return UpdateContractUpdateManager({who: data.toBytes32(1), canManage: data.toBool(33)});\n }\n\n function serialize(UpdateContractUpdateManager memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(UpdateContractType.UpdateManager, t.who, t.canManage);\n }\n\n //---------------------------------------\n // UpdateContract.MaxAssetPriceAge (submsg)\n //---------------------------------------\n\n struct UpdateContractMaxAssetPriceAge {\n uint128 assetId;\n uint64 maxPriceAge;\n }\n\n function deserializeUpdateContractMaxAssetPriceAge(bytes memory data)\n internal\n pure\n returns (UpdateContractMaxAssetPriceAge memory)\n {\n require(updateContractType(data) == UpdateContractType.MaxAssetPriceAge, UnknownMessageType());\n\n return UpdateContractMaxAssetPriceAge({assetId: data.toUint128(1), maxPriceAge: data.toUint64(17)});\n }\n\n function serialize(UpdateContractMaxAssetPriceAge memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(UpdateContractType.MaxAssetPriceAge, t.assetId, t.maxPriceAge);\n }\n\n //---------------------------------------\n // UpdateContract.MaxSharePriceAge (submsg)\n //---------------------------------------\n\n struct UpdateContractMaxSharePriceAge {\n uint64 maxPriceAge;\n }\n\n function deserializeUpdateContractMaxSharePriceAge(bytes memory data)\n internal\n pure\n returns (UpdateContractMaxSharePriceAge memory)\n {\n require(updateContractType(data) == UpdateContractType.MaxSharePriceAge, UnknownMessageType());\n\n return UpdateContractMaxSharePriceAge({maxPriceAge: data.toUint64(1)});\n }\n\n function serialize(UpdateContractMaxSharePriceAge memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(UpdateContractType.MaxSharePriceAge, t.maxPriceAge);\n }\n\n //---------------------------------------\n // UpdateContract.Valuation (submsg)\n //---------------------------------------\n\n struct UpdateContractValuation {\n bytes32 valuation;\n }\n\n function deserializeUpdateContractValuation(bytes memory data)\n internal\n pure\n returns (UpdateContractValuation memory)\n {\n require(updateContractType(data) == UpdateContractType.Valuation, UnknownMessageType());\n\n return UpdateContractValuation({valuation: data.toBytes32(1)});\n }\n\n function serialize(UpdateContractValuation memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(UpdateContractType.Valuation, t.valuation);\n }\n\n //---------------------------------------\n // UpdateContract.SyncDepositMaxReserve (submsg)\n //---------------------------------------\n\n struct UpdateContractSyncDepositMaxReserve {\n uint128 assetId;\n uint128 maxReserve;\n }\n\n function deserializeUpdateContractSyncDepositMaxReserve(bytes memory data)\n internal\n pure\n returns (UpdateContractSyncDepositMaxReserve memory)\n {\n require(updateContractType(data) == UpdateContractType.SyncDepositMaxReserve, UnknownMessageType());\n\n return UpdateContractSyncDepositMaxReserve({assetId: data.toUint128(1), maxReserve: data.toUint128(17)});\n }\n\n function serialize(UpdateContractSyncDepositMaxReserve memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(UpdateContractType.SyncDepositMaxReserve, t.assetId, t.maxReserve);\n }\n\n //---------------------------------------\n // DepositRequest\n //---------------------------------------\n\n struct DepositRequest {\n uint64 poolId;\n bytes16 scId;\n bytes32 investor;\n uint128 assetId;\n uint128 amount;\n }\n\n function deserializeDepositRequest(bytes memory data) internal pure returns (DepositRequest memory) {\n require(messageType(data) == MessageType.DepositRequest, UnknownMessageType());\n return DepositRequest({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n investor: data.toBytes32(25),\n assetId: data.toUint128(57),\n amount: data.toUint128(73)\n });\n }\n\n function serialize(DepositRequest memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.DepositRequest, t.poolId, t.scId, t.investor, t.assetId, t.amount);\n }\n\n //---------------------------------------\n // RedeemRequest\n //---------------------------------------\n\n struct RedeemRequest {\n uint64 poolId;\n bytes16 scId;\n bytes32 investor;\n uint128 assetId;\n uint128 amount;\n }\n\n function deserializeRedeemRequest(bytes memory data) internal pure returns (RedeemRequest memory) {\n require(messageType(data) == MessageType.RedeemRequest, UnknownMessageType());\n return RedeemRequest({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n investor: data.toBytes32(25),\n assetId: data.toUint128(57),\n amount: data.toUint128(73)\n });\n }\n\n function serialize(RedeemRequest memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.RedeemRequest, t.poolId, t.scId, t.investor, t.assetId, t.amount);\n }\n\n //---------------------------------------\n // CancelDepositRequest\n //---------------------------------------\n\n struct CancelDepositRequest {\n uint64 poolId;\n bytes16 scId;\n bytes32 investor;\n uint128 assetId;\n }\n\n function deserializeCancelDepositRequest(bytes memory data) internal pure returns (CancelDepositRequest memory) {\n require(messageType(data) == MessageType.CancelDepositRequest, UnknownMessageType());\n return CancelDepositRequest({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n investor: data.toBytes32(25),\n assetId: data.toUint128(57)\n });\n }\n\n function serialize(CancelDepositRequest memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.CancelDepositRequest, t.poolId, t.scId, t.investor, t.assetId);\n }\n\n //---------------------------------------\n // CancelRedeemRequest\n //---------------------------------------\n\n struct CancelRedeemRequest {\n uint64 poolId;\n bytes16 scId;\n bytes32 investor;\n uint128 assetId;\n }\n\n function deserializeCancelRedeemRequest(bytes memory data) internal pure returns (CancelRedeemRequest memory) {\n require(messageType(data) == MessageType.CancelRedeemRequest, UnknownMessageType());\n return CancelRedeemRequest({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n investor: data.toBytes32(25),\n assetId: data.toUint128(57)\n });\n }\n\n function serialize(CancelRedeemRequest memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.CancelRedeemRequest, t.poolId, t.scId, t.investor, t.assetId);\n }\n\n //---------------------------------------\n // FulfilledDepositRequest\n //---------------------------------------\n\n struct FulfilledDepositRequest {\n uint64 poolId;\n bytes16 scId;\n bytes32 investor;\n uint128 assetId;\n uint128 assetAmount;\n uint128 shareAmount;\n }\n\n function deserializeFulfilledDepositRequest(bytes memory data)\n internal\n pure\n returns (FulfilledDepositRequest memory)\n {\n require(messageType(data) == MessageType.FulfilledDepositRequest, UnknownMessageType());\n return FulfilledDepositRequest({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n investor: data.toBytes32(25),\n assetId: data.toUint128(57),\n assetAmount: data.toUint128(73),\n shareAmount: data.toUint128(89)\n });\n }\n\n function serialize(FulfilledDepositRequest memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(\n MessageType.FulfilledDepositRequest, t.poolId, t.scId, t.investor, t.assetId, t.assetAmount, t.shareAmount\n );\n }\n\n //---------------------------------------\n // FulfilledRedeemRequest\n //---------------------------------------\n\n struct FulfilledRedeemRequest {\n uint64 poolId;\n bytes16 scId;\n bytes32 investor;\n uint128 assetId;\n uint128 assetAmount;\n uint128 shareAmount;\n }\n\n function deserializeFulfilledRedeemRequest(bytes memory data)\n internal\n pure\n returns (FulfilledRedeemRequest memory)\n {\n require(messageType(data) == MessageType.FulfilledRedeemRequest, UnknownMessageType());\n return FulfilledRedeemRequest({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n investor: data.toBytes32(25),\n assetId: data.toUint128(57),\n assetAmount: data.toUint128(73),\n shareAmount: data.toUint128(89)\n });\n }\n\n function serialize(FulfilledRedeemRequest memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(\n MessageType.FulfilledRedeemRequest, t.poolId, t.scId, t.investor, t.assetId, t.assetAmount, t.shareAmount\n );\n }\n\n //---------------------------------------\n // FulfilledCancelDepositRequest\n //---------------------------------------\n\n struct FulfilledCancelDepositRequest {\n uint64 poolId;\n bytes16 scId;\n bytes32 investor;\n uint128 assetId;\n uint128 cancelledAmount;\n }\n\n function deserializeFulfilledCancelDepositRequest(bytes memory data)\n internal\n pure\n returns (FulfilledCancelDepositRequest memory)\n {\n require(messageType(data) == MessageType.FulfilledCancelDepositRequest, UnknownMessageType());\n return FulfilledCancelDepositRequest({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n investor: data.toBytes32(25),\n assetId: data.toUint128(57),\n cancelledAmount: data.toUint128(73)\n });\n }\n\n function serialize(FulfilledCancelDepositRequest memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(\n MessageType.FulfilledCancelDepositRequest, t.poolId, t.scId, t.investor, t.assetId, t.cancelledAmount\n );\n }\n\n //---------------------------------------\n // FulfilledCancelRedeemRequest\n //---------------------------------------\n\n struct FulfilledCancelRedeemRequest {\n uint64 poolId;\n bytes16 scId;\n bytes32 investor;\n uint128 assetId;\n uint128 cancelledShares;\n }\n\n function deserializeFulfilledCancelRedeemRequest(bytes memory data)\n internal\n pure\n returns (FulfilledCancelRedeemRequest memory)\n {\n require(messageType(data) == MessageType.FulfilledCancelRedeemRequest, UnknownMessageType());\n return FulfilledCancelRedeemRequest({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n investor: data.toBytes32(25),\n assetId: data.toUint128(57),\n cancelledShares: data.toUint128(73)\n });\n }\n\n function serialize(FulfilledCancelRedeemRequest memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(\n MessageType.FulfilledCancelRedeemRequest, t.poolId, t.scId, t.investor, t.assetId, t.cancelledShares\n );\n }\n\n //---------------------------------------\n // UpdateHoldingAmount\n //---------------------------------------\n\n struct UpdateHoldingAmount {\n uint64 poolId;\n bytes16 scId;\n uint128 assetId;\n bytes32 who;\n uint128 amount;\n uint128 pricePerUnit;\n uint64 timestamp;\n bool isIncrease; // Signals whether this is an increase or a decrease\n }\n\n function deserializeUpdateHoldingAmount(bytes memory data) internal pure returns (UpdateHoldingAmount memory h) {\n require(messageType(data) == MessageType.UpdateHoldingAmount, \"UnknownMessageType\");\n\n return UpdateHoldingAmount({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n assetId: data.toUint128(25),\n who: data.toBytes32(41),\n amount: data.toUint128(73),\n pricePerUnit: data.toUint128(89),\n timestamp: data.toUint64(105),\n isIncrease: data.toBool(113)\n });\n }\n\n function serialize(UpdateHoldingAmount memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(\n MessageType.UpdateHoldingAmount,\n t.poolId,\n t.scId,\n t.assetId,\n t.who,\n t.amount,\n t.pricePerUnit,\n t.timestamp,\n t.isIncrease\n );\n }\n\n //---------------------------------------\n // UpdateShares\n //---------------------------------------\n\n struct UpdateShares {\n uint64 poolId;\n bytes16 scId;\n uint128 shares;\n uint64 timestamp;\n bool isIssuance;\n }\n\n function deserializeUpdateShares(bytes memory data) internal pure returns (UpdateShares memory) {\n require(messageType(data) == MessageType.UpdateShares, UnknownMessageType());\n\n return UpdateShares({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n shares: data.toUint128(25),\n timestamp: data.toUint64(41),\n isIssuance: data.toBool(49)\n });\n }\n\n function serialize(UpdateShares memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.UpdateShares, t.poolId, t.scId, t.shares, t.timestamp, t.isIssuance);\n }\n\n //---------------------------------------\n // ApprovedDeposits\n //---------------------------------------\n\n struct ApprovedDeposits {\n uint64 poolId;\n bytes16 scId;\n uint128 assetId;\n uint128 assetAmount;\n uint128 pricePoolPerAsset;\n }\n\n function deserializeApprovedDeposits(bytes memory data) internal pure returns (ApprovedDeposits memory) {\n require(messageType(data) == MessageType.ApprovedDeposits, UnknownMessageType());\n\n return ApprovedDeposits({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n assetId: data.toUint128(25),\n assetAmount: data.toUint128(41),\n pricePoolPerAsset: data.toUint128(57)\n });\n }\n\n function serialize(ApprovedDeposits memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(\n MessageType.ApprovedDeposits, t.poolId, t.scId, t.assetId, t.assetAmount, t.pricePoolPerAsset\n );\n }\n\n //---------------------------------------\n // IssuedShares\n //---------------------------------------\n\n struct IssuedShares {\n uint64 poolId;\n bytes16 scId;\n uint128 shareAmount;\n uint128 pricePoolPerShare;\n }\n\n function deserializeIssuedShares(bytes memory data) internal pure returns (IssuedShares memory) {\n require(messageType(data) == MessageType.IssuedShares, UnknownMessageType());\n\n return IssuedShares({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n shareAmount: data.toUint128(25),\n pricePoolPerShare: data.toUint128(41)\n });\n }\n\n function serialize(IssuedShares memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.IssuedShares, t.poolId, t.scId, t.shareAmount, t.pricePoolPerShare);\n }\n\n //---------------------------------------\n // RevokedShares\n //---------------------------------------\n\n struct RevokedShares {\n uint64 poolId;\n bytes16 scId;\n uint128 assetId;\n uint128 shareAmount;\n uint128 pricePoolPerShare;\n uint128 assetAmount;\n }\n\n function deserializeRevokedShares(bytes memory data) internal pure returns (RevokedShares memory) {\n require(messageType(data) == MessageType.RevokedShares, UnknownMessageType());\n\n return RevokedShares({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n assetId: data.toUint128(25),\n assetAmount: data.toUint128(41),\n shareAmount: data.toUint128(57),\n pricePoolPerShare: data.toUint128(73)\n });\n }\n\n function serialize(RevokedShares memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(\n MessageType.RevokedShares, t.poolId, t.scId, t.assetId, t.assetAmount, t.shareAmount, t.pricePoolPerShare\n );\n }\n\n //---------------------------------------\n // TriggerIssueShares\n //---------------------------------------\n\n struct TriggerIssueShares {\n uint64 poolId;\n bytes16 scId;\n bytes32 who;\n uint128 shares;\n }\n\n function deserializeTriggerIssueShares(bytes memory data) internal pure returns (TriggerIssueShares memory) {\n require(messageType(data) == MessageType.TriggerIssueShares, UnknownMessageType());\n\n return TriggerIssueShares({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n who: data.toBytes32(25),\n shares: data.toUint128(57)\n });\n }\n\n function serialize(TriggerIssueShares memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.TriggerIssueShares, t.poolId, t.scId, t.who, t.shares);\n }\n\n //---------------------------------------\n // TriggerSubmitQueuedShares\n //---------------------------------------\n\n struct TriggerSubmitQueuedShares {\n uint64 poolId;\n bytes16 scId;\n }\n\n function deserializeTriggerSubmitQueuedShares(bytes memory data)\n internal\n pure\n returns (TriggerSubmitQueuedShares memory)\n {\n require(messageType(data) == MessageType.TriggerSubmitQueuedShares, UnknownMessageType());\n return TriggerSubmitQueuedShares({poolId: data.toUint64(1), scId: data.toBytes16(9)});\n }\n\n function serialize(TriggerSubmitQueuedShares memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.TriggerSubmitQueuedShares, t.poolId, t.scId);\n }\n\n //---------------------------------------\n // TriggerSubmitQueuedAssets\n //---------------------------------------\n\n struct TriggerSubmitQueuedAssets {\n uint64 poolId;\n bytes16 scId;\n uint128 assetId;\n }\n\n function deserializeTriggerSubmitQueuedAssets(bytes memory data)\n internal\n pure\n returns (TriggerSubmitQueuedAssets memory)\n {\n require(messageType(data) == MessageType.TriggerSubmitQueuedAssets, UnknownMessageType());\n return\n TriggerSubmitQueuedAssets({poolId: data.toUint64(1), scId: data.toBytes16(9), assetId: data.toUint128(25)});\n }\n\n function serialize(TriggerSubmitQueuedAssets memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.TriggerSubmitQueuedAssets, t.poolId, t.scId, t.assetId);\n }\n\n //---------------------------------------\n // SetQueue\n //---------------------------------------\n\n struct SetQueue {\n uint64 poolId;\n bytes16 scId;\n bool enabled;\n }\n\n function deserializeSetQueue(bytes memory data) internal pure returns (SetQueue memory) {\n require(messageType(data) == MessageType.SetQueue, UnknownMessageType());\n return SetQueue({poolId: data.toUint64(1), scId: data.toBytes16(9), enabled: data.toBool(25)});\n }\n\n function serialize(SetQueue memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.SetQueue, t.poolId, t.scId, t.enabled);\n }\n}\n" + }, + "src/common/libraries/MessageProofLib.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\n\nlibrary MessageProofLib {\n using BytesLib for bytes;\n\n uint8 constant MESSAGE_PROOF_ID = 1;\n\n error UnknownMessageProofType();\n\n function deserializeMessageProof(bytes memory data) internal pure returns (bytes32) {\n require(data.toUint8(0) == MESSAGE_PROOF_ID, UnknownMessageProofType());\n return data.toBytes32(1);\n }\n\n function serializeMessageProof(bytes32 hash) internal pure returns (bytes memory) {\n return abi.encodePacked(MESSAGE_PROOF_ID, hash);\n }\n}\n" + }, + "src/common/libraries/PricingLib.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {IERC20Metadata} from \"src/misc/interfaces/IERC20.sol\";\nimport {IERC6909MetadataExt} from \"src/misc/interfaces/IERC6909.sol\";\nimport {D18, d18} from \"src/misc/types/D18.sol\";\n\nimport {PricingLib} from \"src/common/libraries/PricingLib.sol\";\n\nlibrary PricingLib {\n using MathLib for *;\n\n /// @dev Prices are fixed-point integers with 18 decimals\n uint8 internal constant PRICE_DECIMALS = 18;\n\n /// -----------------------------------------------------\n /// View Methods\n /// -----------------------------------------------------\n\n /// @dev Converts the given asset amount to share amount. Returned value is in share decimals.\n ///\n /// @dev NOTE: MUST ONLY be used in AsyncRequestManager which rely on priceAssetPerShare that is derived from\n /// Fulfilled*\n /// message amounts. Any other codepath must use the variant with pricePoolPerAsset and pricePoolPerShare\n function assetToShareAmount(\n address shareToken,\n address asset,\n uint256 tokenId,\n uint128 assetAmount,\n D18 priceAssetPerShare_,\n MathLib.Rounding rounding\n ) internal view returns (uint128 shares) {\n if (assetAmount == 0 || priceAssetPerShare_.raw() == 0) {\n return 0;\n }\n\n uint8 assetDecimals = getAssetDecimals(asset, tokenId);\n uint8 shareDecimals = IERC20Metadata(shareToken).decimals();\n\n return PricingLib.convertWithReciprocalPrice(\n assetAmount, assetDecimals, shareDecimals, priceAssetPerShare_, rounding\n ).toUint128();\n }\n\n /// @dev Converts the given asset amount to share amount. Returned value is in share decimals.\n function assetToShareAmount(\n address shareToken,\n address asset,\n uint256 tokenId,\n uint128 assetAmount,\n D18 pricePoolPerAsset,\n D18 pricePoolPerShare,\n MathLib.Rounding rounding\n ) internal view returns (uint128 shares) {\n if (assetAmount == 0 || pricePoolPerShare.raw() == 0 || pricePoolPerAsset.raw() == 0) {\n return 0;\n }\n\n uint8 assetDecimals = getAssetDecimals(asset, tokenId);\n uint8 shareDecimals = IERC20Metadata(shareToken).decimals();\n\n return PricingLib.assetToShareAmount(\n assetAmount, assetDecimals, shareDecimals, pricePoolPerAsset, pricePoolPerShare, rounding\n ).toUint128();\n }\n\n /// @dev Converts the given share amount to asset amount. Returned value is in share decimals.\n ///\n /// @dev NOTE: MUST ONLY be used in AsyncRequestManager which rely on priceAssetPerShare that is derived from\n /// Fulfilled*\n /// message amounts. Any other codepath must use the variant with pricePoolPerAsset and pricePoolPerShare\n function shareToAssetAmount(\n address shareToken,\n uint128 shareAmount,\n address asset,\n uint256 tokenId,\n D18 priceAssetPerShare_,\n MathLib.Rounding rounding\n ) internal view returns (uint128 shares) {\n if (shareAmount == 0 || priceAssetPerShare_.raw() == 0) {\n return 0;\n }\n\n uint8 assetDecimals = getAssetDecimals(asset, tokenId);\n uint8 shareDecimals = IERC20Metadata(shareToken).decimals();\n\n return PricingLib.convertWithPrice(shareAmount, shareDecimals, assetDecimals, priceAssetPerShare_, rounding)\n .toUint128();\n }\n\n /// @dev Converts the given share amount to asset amount. Returned value is in share decimals.\n function shareToAssetAmount(\n address shareToken,\n uint128 shareAmount,\n address asset,\n uint256 tokenId,\n D18 pricePoolPerAsset,\n D18 pricePoolPerShare,\n MathLib.Rounding rounding\n ) internal view returns (uint128 shares) {\n if (shareAmount == 0 || pricePoolPerShare.raw() == 0 || pricePoolPerAsset.raw() == 0) {\n return 0;\n }\n\n uint8 assetDecimals = getAssetDecimals(asset, tokenId);\n uint8 shareDecimals = IERC20Metadata(shareToken).decimals();\n\n return PricingLib.shareToAssetAmount(\n shareAmount, shareDecimals, assetDecimals, pricePoolPerAsset, pricePoolPerShare, rounding\n ).toUint128();\n }\n\n /// @dev Calculates the asset price per share returns the value in price decimals\n /// Denominated in ASSET_UNIT/SHARE_UNIT\n function calculatePriceAssetPerShare(\n address shareToken,\n uint128 shares,\n address asset,\n uint256 tokenId,\n uint128 assets,\n MathLib.Rounding rounding\n ) internal view returns (uint256 priceAssetPerShare_) {\n if (assets == 0 || shares == 0) {\n return 0;\n }\n\n uint8 assetDecimals = getAssetDecimals(asset, tokenId);\n uint8 shareDecimals = IERC20Metadata(shareToken).decimals();\n\n // NOTE: More precise than d18(assets * 10 ** assetDecimals, shares * 10 ** shareDecimals)\n return toPriceDecimals(assets, assetDecimals).mulDiv(\n 10 ** PRICE_DECIMALS, toPriceDecimals(shares, shareDecimals), rounding\n );\n }\n\n /// -----------------------------------------------------\n /// Pure Methods\n /// -----------------------------------------------------\n\n /// @dev Converts an amount using decimals and price with implicit rounding down\n function convertWithPrice(uint256 baseAmount, uint8 baseDecimals, uint8 quoteDecimals, D18 priceQuotePerBase)\n internal\n pure\n returns (uint256 quoteAmount)\n {\n return convertWithPrice(baseAmount, baseDecimals, quoteDecimals, priceQuotePerBase, MathLib.Rounding.Down);\n }\n\n /// @dev Converts an amount using decimals and price with explicit rounding.\n function convertWithPrice(\n uint256 baseAmount,\n uint8 baseDecimals,\n uint8 quoteDecimals,\n D18 priceQuotePerBase,\n MathLib.Rounding rounding\n ) internal pure returns (uint256 quoteAmount) {\n if (baseDecimals == quoteDecimals) {\n return priceQuotePerBase.mulUint256(baseAmount, rounding);\n }\n\n return\n priceQuotePerBase.mulUint256(MathLib.mulDiv(baseAmount, 10 ** quoteDecimals, 10 ** baseDecimals), rounding);\n }\n\n /// @dev Converts an amount using decimals and reciprocal price.\n ///\n /// NOTE: More precise than convertWithPrice(,,,price.reciprocal,)\n function convertWithReciprocalPrice(\n uint256 baseAmount,\n uint8 baseDecimals,\n uint8 quoteDecimals,\n D18 priceBasePerQuote,\n MathLib.Rounding rounding\n ) internal pure returns (uint256 quoteAmount) {\n if (baseDecimals == quoteDecimals) {\n return priceBasePerQuote.reciprocalMulUint256(baseAmount, rounding);\n }\n\n return priceBasePerQuote.reciprocalMulUint256(\n MathLib.mulDiv(baseAmount, 10 ** quoteDecimals, 10 ** baseDecimals), rounding\n );\n }\n\n /// @dev Converts asset amount to share amount.\n function assetToShareAmount(\n uint256 assetAmount,\n uint8 assetDecimals,\n uint8 shareDecimals,\n D18 pricePoolPerAsset,\n D18 pricePoolPerShare,\n MathLib.Rounding rounding\n ) internal pure returns (uint256 shareAmount) {\n return pricePoolPerShare.reciprocalMulUint256(\n convertWithPrice(assetAmount, assetDecimals, shareDecimals, pricePoolPerAsset, MathLib.Rounding.Down),\n rounding\n );\n }\n\n /// @dev Converts share amount to asset asset amount.\n function shareToAssetAmount(\n uint256 shareAmount,\n uint8 shareDecimals,\n uint8 assetDecimals,\n D18 pricePoolPerAsset,\n D18 pricePoolPerShare,\n MathLib.Rounding rounding\n ) internal pure returns (uint256 assetAmount) {\n return convertWithReciprocalPrice(\n pricePoolPerShare.mulUint256(shareAmount, MathLib.Rounding.Down),\n shareDecimals,\n assetDecimals,\n pricePoolPerAsset,\n rounding\n );\n }\n\n /// @dev Converts pool amount to asset amount.\n function poolToAssetAmount(\n uint256 poolAmount,\n uint8 poolDecimals,\n uint8 assetDecimals,\n D18 pricePoolPerAsset,\n MathLib.Rounding rounding\n ) internal pure returns (uint256 assetAmount) {\n return convertWithReciprocalPrice(poolAmount, poolDecimals, assetDecimals, pricePoolPerAsset, rounding);\n }\n\n /// @dev Returns the asset price per share denominated in ASSET_UNIT/SHARE_UNIT\n ///\n /// @dev NOTE: Should never be used for calculating amounts due to precision loss. Instead, please refer to\n /// conversion relying on pricePoolPerShare and pricePoolPerAsset.\n function priceAssetPerShare(D18 pricePoolPerShare, D18 pricePoolPerAsset)\n internal\n pure\n returns (D18 priceAssetPerShare_)\n {\n return pricePoolPerShare / pricePoolPerAsset;\n }\n\n /// -----------------------------------------------------\n /// Private Methods\n /// -----------------------------------------------------\n\n /// @dev Returns the asset decimals\n function getAssetDecimals(address asset, uint256 tokenId) private view returns (uint8 assetDecimals) {\n return tokenId == 0 ? IERC20Metadata(asset).decimals() : IERC6909MetadataExt(asset).decimals(tokenId);\n }\n\n /// @dev When converting assets to shares using the price, all values are normalized to PRICE_DECIMALS\n /// @dev NOTE: We require all assets to have 2 <= decimals <= 18, see `PoolManager.registerAsset`\n function toPriceDecimals(uint128 _value, uint8 decimals) private pure returns (uint256) {\n if (PRICE_DECIMALS == decimals) return uint256(_value);\n return uint256(_value) * 10 ** (PRICE_DECIMALS - decimals);\n }\n\n /// @dev Converts decimals of the value from the price decimals back to the intended decimals\n /// @dev NOTE: We require all assets to have 2 <= decimals <= 18, see `PoolManager.registerAsset`\n function fromPriceDecimals(uint256 _value, uint8 decimals) private pure returns (uint128) {\n if (PRICE_DECIMALS == decimals) return _value.toUint128();\n return (_value / 10 ** (PRICE_DECIMALS - decimals)).toUint128();\n }\n}\n" + }, + "src/common/types/AccountId.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\ntype AccountId is uint32;\n\nfunction raw(AccountId accountId_) pure returns (uint32) {\n return AccountId.unwrap(accountId_);\n}\n\nusing {raw} for AccountId global;\n" + }, + "src/common/types/AssetId.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\n/// @dev Composite Id of the centrifugeId (uint16) where the asset resides\n/// and a local counter (uint64) that is part of the contract that registers the asset.\ntype AssetId is uint128;\n\nfunction isNull(AssetId assetId) pure returns (bool) {\n return AssetId.unwrap(assetId) == 0;\n}\n\nfunction addr(AssetId assetId) pure returns (address) {\n return address(uint160(AssetId.unwrap(assetId)));\n}\n\nfunction raw(AssetId assetId) pure returns (uint128) {\n return AssetId.unwrap(assetId);\n}\n\nfunction centrifugeId(AssetId assetId) pure returns (uint16) {\n return uint16(AssetId.unwrap(assetId) >> 112);\n}\n\nfunction newAssetId(uint16 centrifugeId_, uint64 counter) pure returns (AssetId) {\n return AssetId.wrap((uint128(centrifugeId_) << 112) + counter);\n}\n\nfunction newAssetId(uint32 isoCode) pure returns (AssetId) {\n return AssetId.wrap(isoCode);\n}\n\nfunction eq(AssetId a, AssetId b) pure returns (bool) {\n return a.raw() == b.raw();\n}\n\nusing {isNull, addr, raw, centrifugeId, eq} for AssetId global;\n" + }, + "src/common/types/PoolId.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\n\nusing MathLib for uint256;\n\ntype PoolId is uint64;\n\nfunction centrifugeId(PoolId poolId) pure returns (uint16) {\n return uint16(PoolId.unwrap(poolId) >> 48);\n}\n\nfunction newPoolId(uint16 centrifugeId_, uint48 localPoolId) pure returns (PoolId) {\n return PoolId.wrap((uint64(centrifugeId_) << 48) | uint64(localPoolId));\n}\n\nfunction isNull(PoolId poolId) pure returns (bool) {\n return PoolId.unwrap(poolId) == 0;\n}\n\nfunction raw(PoolId poolId) pure returns (uint64) {\n return PoolId.unwrap(poolId);\n}\n\nusing {centrifugeId, isNull, raw} for PoolId global;\n" + }, + "src/common/types/ShareClassId.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\n\ntype ShareClassId is bytes16;\n\nfunction isNull(ShareClassId scId) pure returns (bool) {\n return ShareClassId.unwrap(scId) == 0;\n}\n\nfunction equals(ShareClassId left, ShareClassId right) pure returns (bool) {\n return ShareClassId.unwrap(left) == ShareClassId.unwrap(right);\n}\n\nfunction raw(ShareClassId scId) pure returns (bytes16) {\n return ShareClassId.unwrap(scId);\n}\n\nfunction newShareClassId(PoolId poolId, uint32 index) pure returns (ShareClassId scId) {\n return ShareClassId.wrap(bytes16((uint128(PoolId.unwrap(poolId)) << 64) + index));\n}\n\nusing {isNull, raw, equals as ==} for ShareClassId global;\n" + }, + "src/hooks/FreezeOnly.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\nimport {BitmapLib} from \"src/misc/libraries/BitmapLib.sol\";\nimport {IERC165} from \"src/misc/interfaces/IERC7575.sol\";\n\nimport {IRoot} from \"src/common/interfaces/IRoot.sol\";\nimport {UpdateRestrictionType, MessageLib} from \"src/common/libraries/MessageLib.sol\";\n\nimport {IHook, HookData} from \"src/common/interfaces/IHook.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\n\nimport {IFreezable} from \"src/hooks/interfaces/IFreezable.sol\";\n\n/// @title Freeze Only\n/// @notice Hook implementation that:\n/// * Allows any non-frozen account to receive tokens and transfer tokens\n/// * Supports freezing accounts which blocks transfers both to and from them\n/// * Allows authTransferFrom calls\n///\n/// @dev The last bit of hookData is used to denote whether the account is frozen.\ncontract FreezeOnly is Auth, IFreezable, IHook {\n using BitmapLib for *;\n using MessageLib for *;\n using BytesLib for bytes;\n using CastLib for bytes32;\n\n /// @dev Least significant bit\n uint8 public constant FREEZE_BIT = 0;\n\n IRoot public immutable root;\n\n constructor(address root_, address deployer) Auth(deployer) {\n root = IRoot(root_);\n }\n\n //----------------------------------------------------------------------------------------------\n // Callback from share token\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHook\n function onERC20Transfer(address from, address to, uint256 value, HookData calldata hookData)\n external\n virtual\n returns (bytes4)\n {\n require(checkERC20Transfer(from, to, value, hookData), TransferBlocked());\n return IHook.onERC20Transfer.selector;\n }\n\n /// @inheritdoc IHook\n function onERC20AuthTransfer(\n address, /* sender */\n address, /* from */\n address, /* to */\n uint256, /* value */\n HookData calldata /* hookData */\n ) external pure returns (bytes4) {\n return IHook.onERC20AuthTransfer.selector;\n }\n\n /// @inheritdoc IHook\n function checkERC20Transfer(address from, address, /* to */ uint256, /* value */ HookData calldata hookData)\n public\n view\n returns (bool)\n {\n uint128 fromHookData = uint128(hookData.from);\n if (fromHookData.getBit(FREEZE_BIT) == true && !root.endorsed(from)) {\n // Source is frozen and not endorsed\n return false;\n }\n\n uint128 toHookData = uint128(hookData.to);\n if (toHookData.getBit(FREEZE_BIT) == true) {\n // Destination is frozen\n return false;\n }\n\n return true;\n }\n\n //----------------------------------------------------------------------------------------------\n // Restriction updates\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHook\n function updateRestriction(address token, bytes memory payload) external auth {\n UpdateRestrictionType updateId = payload.updateRestrictionType();\n\n if (updateId == UpdateRestrictionType.Freeze) {\n MessageLib.UpdateRestrictionFreeze memory m = payload.deserializeUpdateRestrictionFreeze();\n freeze(token, m.user.toAddress());\n } else if (updateId == UpdateRestrictionType.Unfreeze) {\n MessageLib.UpdateRestrictionUnfreeze memory m = payload.deserializeUpdateRestrictionUnfreeze();\n unfreeze(token, m.user.toAddress());\n } else {\n revert InvalidUpdate();\n }\n }\n\n /// @inheritdoc IFreezable\n function freeze(address token, address user) public auth {\n require(user != address(0), CannotFreezeZeroAddress());\n require(!root.endorsed(user), EndorsedUserCannotBeFrozen());\n\n uint128 hookData = uint128(IShareToken(token).hookDataOf(user));\n IShareToken(token).setHookData(user, bytes16(hookData.setBit(FREEZE_BIT, true)));\n\n emit Freeze(token, user);\n }\n\n /// @inheritdoc IFreezable\n function unfreeze(address token, address user) public auth {\n uint128 hookData = uint128(IShareToken(token).hookDataOf(user));\n IShareToken(token).setHookData(user, bytes16(hookData.setBit(FREEZE_BIT, false)));\n\n emit Unfreeze(token, user);\n }\n\n /// @inheritdoc IFreezable\n function isFrozen(address token, address user) public view returns (bool) {\n return uint128(IShareToken(token).hookDataOf(user)).getBit(FREEZE_BIT);\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-165\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC165\n function supportsInterface(bytes4 interfaceId) external pure override returns (bool) {\n return interfaceId == type(IHook).interfaceId || interfaceId == type(IERC165).interfaceId;\n }\n}\n" + }, + "src/hooks/FullRestrictions.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {BitmapLib} from \"src/misc/libraries/BitmapLib.sol\";\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\nimport {IERC165} from \"src/misc/interfaces/IERC7575.sol\";\n\nimport {UpdateRestrictionType, MessageLib} from \"src/common/libraries/MessageLib.sol\";\nimport {IRoot} from \"src/common/interfaces/IRoot.sol\";\n\nimport {IHook, HookData, ESCROW_HOOK_ID} from \"src/common/interfaces/IHook.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\n\nimport {IFreezable} from \"src/hooks/interfaces/IFreezable.sol\";\nimport {IMemberlist} from \"src/hooks/interfaces/IMemberlist.sol\";\n\n/// @title Full Restrictions\n/// @notice Hook implementation that:\n/// * Requires adding accounts to the memberlist before they can receive tokens\n/// * Supports freezing accounts which blocks transfers both to and from them\n/// * Allows authTransferFrom calls\n///\n/// @dev The first 8 bytes (uint64) of hookData is used for the memberlist valid until date,\n/// the last bit is used to denote whether the account is frozen.\ncontract FullRestrictions is Auth, IMemberlist, IFreezable, IHook {\n using BitmapLib for *;\n using MessageLib for *;\n using BytesLib for bytes;\n using CastLib for bytes32;\n\n /// @dev Least significant bit\n uint8 public constant FREEZE_BIT = 0;\n\n IRoot public immutable root;\n\n constructor(address root_, address deployer) Auth(deployer) {\n root = IRoot(root_);\n }\n\n //----------------------------------------------------------------------------------------------\n // Callback from share token\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHook\n function onERC20Transfer(address from, address to, uint256 value, HookData calldata hookData)\n external\n virtual\n returns (bytes4)\n {\n require(checkERC20Transfer(from, to, value, hookData), TransferBlocked());\n return IHook.onERC20Transfer.selector;\n }\n\n /// @inheritdoc IHook\n function onERC20AuthTransfer(\n address, /* sender */\n address, /* from */\n address, /* to */\n uint256, /* value */\n HookData calldata /* hookData */\n ) external pure returns (bytes4) {\n return IHook.onERC20AuthTransfer.selector;\n }\n\n /// @inheritdoc IHook\n function checkERC20Transfer(address from, address to, uint256, /* value */ HookData calldata hookData)\n public\n view\n returns (bool)\n {\n if (uint128(hookData.from).getBit(FREEZE_BIT) == true && !root.endorsed(from) && from != ESCROW_HOOK_ID) {\n // Source is frozen and not endorsed\n return false;\n }\n\n if (root.endorsed(to) || to == address(0) || to == ESCROW_HOOK_ID) {\n // Destination is endorsed or escrow and source was already checked, so the transfer is allowed\n return true;\n }\n\n uint128 toHookData = uint128(hookData.to);\n if (toHookData.getBit(FREEZE_BIT) == true) {\n // Destination is frozen\n return false;\n }\n\n if (toHookData >> 64 < block.timestamp) {\n // Destination is not a member\n return false;\n }\n\n return true;\n }\n\n //----------------------------------------------------------------------------------------------\n // Restriction updates\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHook\n function updateRestriction(address token, bytes memory payload) external auth {\n UpdateRestrictionType updateId = payload.updateRestrictionType();\n\n if (updateId == UpdateRestrictionType.Member) {\n MessageLib.UpdateRestrictionMember memory m = payload.deserializeUpdateRestrictionMember();\n updateMember(token, m.user.toAddress(), m.validUntil);\n } else if (updateId == UpdateRestrictionType.Freeze) {\n MessageLib.UpdateRestrictionFreeze memory m = payload.deserializeUpdateRestrictionFreeze();\n freeze(token, m.user.toAddress());\n } else if (updateId == UpdateRestrictionType.Unfreeze) {\n MessageLib.UpdateRestrictionUnfreeze memory m = payload.deserializeUpdateRestrictionUnfreeze();\n unfreeze(token, m.user.toAddress());\n } else {\n revert InvalidUpdate();\n }\n }\n\n /// @inheritdoc IFreezable\n function freeze(address token, address user) public auth {\n require(user != address(0), CannotFreezeZeroAddress());\n require(!root.endorsed(user), EndorsedUserCannotBeFrozen());\n\n uint128 hookData = uint128(IShareToken(token).hookDataOf(user));\n IShareToken(token).setHookData(user, bytes16(hookData.setBit(FREEZE_BIT, true)));\n\n emit Freeze(token, user);\n }\n\n /// @inheritdoc IFreezable\n function unfreeze(address token, address user) public auth {\n uint128 hookData = uint128(IShareToken(token).hookDataOf(user));\n IShareToken(token).setHookData(user, bytes16(hookData.setBit(FREEZE_BIT, false)));\n\n emit Unfreeze(token, user);\n }\n\n /// @inheritdoc IFreezable\n function isFrozen(address token, address user) public view returns (bool) {\n return uint128(IShareToken(token).hookDataOf(user)).getBit(FREEZE_BIT);\n }\n\n /// @inheritdoc IMemberlist\n function updateMember(address token, address user, uint64 validUntil) public auth {\n require(block.timestamp <= validUntil, InvalidValidUntil());\n require(!root.endorsed(user), EndorsedUserCannotBeUpdated());\n\n uint128 hookData = uint128(validUntil) << 64;\n hookData.setBit(FREEZE_BIT, isFrozen(token, user));\n IShareToken(token).setHookData(user, bytes16(hookData));\n\n emit UpdateMember(token, user, validUntil);\n }\n\n /// @inheritdoc IMemberlist\n function isMember(address token, address user) external view returns (bool isValid, uint64 validUntil) {\n validUntil = abi.encodePacked(IShareToken(token).hookDataOf(user)).toUint64(0);\n isValid = validUntil >= block.timestamp;\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-165\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC165\n function supportsInterface(bytes4 interfaceId) external pure override returns (bool) {\n return interfaceId == type(IHook).interfaceId || interfaceId == type(IERC165).interfaceId;\n }\n}\n" + }, + "src/hooks/RedemptionRestrictions.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\nimport {BitmapLib} from \"src/misc/libraries/BitmapLib.sol\";\nimport {IERC165} from \"src/misc/interfaces/IERC7575.sol\";\n\nimport {IRoot} from \"src/common/interfaces/IRoot.sol\";\nimport {UpdateRestrictionType, MessageLib} from \"src/common/libraries/MessageLib.sol\";\n\nimport {IHook, HookData, ESCROW_HOOK_ID} from \"src/common/interfaces/IHook.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\n\nimport {IFreezable} from \"src/hooks/interfaces/IFreezable.sol\";\nimport {IMemberlist} from \"src/hooks/interfaces/IMemberlist.sol\";\n\n/// @title Redemption Restrictions\n/// @notice Hook implementation that:\n/// * Allows any non-frozen account to receive tokens and transfer tokens\n/// * Requires accounts to be added as a member before submitting a redemption request\n/// * Supports freezing accounts which blocks transfers both to and from them\n/// * Allows authTransferFrom calls\n///\n/// @dev The first 8 bytes (uint64) of hookData is used for the memberlist valid until date,\n/// the last bit is used to denote whether the account is frozen.\ncontract RedemptionRestrictions is Auth, IMemberlist, IFreezable, IHook {\n using BitmapLib for *;\n using MessageLib for *;\n using BytesLib for bytes;\n using CastLib for bytes32;\n\n /// @dev Least significant bit\n uint8 public constant FREEZE_BIT = 0;\n\n IRoot public immutable root;\n\n constructor(address root_, address deployer) Auth(deployer) {\n root = IRoot(root_);\n }\n\n //----------------------------------------------------------------------------------------------\n // Callback from share token\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHook\n function onERC20Transfer(address from, address to, uint256 value, HookData calldata hookData)\n external\n virtual\n returns (bytes4)\n {\n require(checkERC20Transfer(from, to, value, hookData), TransferBlocked());\n return IHook.onERC20Transfer.selector;\n }\n\n /// @inheritdoc IHook\n function onERC20AuthTransfer(\n address, /* sender */\n address, /* from */\n address, /* to */\n uint256, /* value */\n HookData calldata /* hookData */\n ) external pure returns (bytes4) {\n return IHook.onERC20AuthTransfer.selector;\n }\n\n /// @inheritdoc IHook\n function checkERC20Transfer(address from, address to, uint256, /* value */ HookData calldata hookData)\n public\n view\n returns (bool)\n {\n uint128 fromHookData = uint128(hookData.from);\n if (fromHookData.getBit(FREEZE_BIT) == true && !root.endorsed(from)) {\n // Source is frozen and not endorsed\n return false;\n }\n\n uint128 toHookData = uint128(hookData.to);\n if (toHookData.getBit(FREEZE_BIT) == true) {\n // Destination is frozen\n return false;\n }\n\n if (from == address(0) && to == ESCROW_HOOK_ID) {\n // Deposit request fulfillment\n return true;\n }\n\n if (to == ESCROW_HOOK_ID && fromHookData >> 64 < block.timestamp) {\n // Destination is escrow, so it's a redemption request, and the user is not a member\n return false;\n }\n\n return true;\n }\n\n //----------------------------------------------------------------------------------------------\n // Restriction updates\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHook\n function updateRestriction(address token, bytes memory payload) external auth {\n UpdateRestrictionType updateId = payload.updateRestrictionType();\n\n if (updateId == UpdateRestrictionType.Member) {\n MessageLib.UpdateRestrictionMember memory m = payload.deserializeUpdateRestrictionMember();\n updateMember(token, m.user.toAddress(), m.validUntil);\n } else if (updateId == UpdateRestrictionType.Freeze) {\n MessageLib.UpdateRestrictionFreeze memory m = payload.deserializeUpdateRestrictionFreeze();\n freeze(token, m.user.toAddress());\n } else if (updateId == UpdateRestrictionType.Unfreeze) {\n MessageLib.UpdateRestrictionUnfreeze memory m = payload.deserializeUpdateRestrictionUnfreeze();\n unfreeze(token, m.user.toAddress());\n } else {\n revert InvalidUpdate();\n }\n }\n\n /// @inheritdoc IFreezable\n function freeze(address token, address user) public auth {\n require(user != address(0), CannotFreezeZeroAddress());\n require(!root.endorsed(user), EndorsedUserCannotBeFrozen());\n\n uint128 hookData = uint128(IShareToken(token).hookDataOf(user));\n IShareToken(token).setHookData(user, bytes16(hookData.setBit(FREEZE_BIT, true)));\n\n emit Freeze(token, user);\n }\n\n /// @inheritdoc IFreezable\n function unfreeze(address token, address user) public auth {\n uint128 hookData = uint128(IShareToken(token).hookDataOf(user));\n IShareToken(token).setHookData(user, bytes16(hookData.setBit(FREEZE_BIT, false)));\n\n emit Unfreeze(token, user);\n }\n\n /// @inheritdoc IFreezable\n function isFrozen(address token, address user) public view returns (bool) {\n return uint128(IShareToken(token).hookDataOf(user)).getBit(FREEZE_BIT);\n }\n\n /// @inheritdoc IMemberlist\n function updateMember(address token, address user, uint64 validUntil) public auth {\n require(block.timestamp <= validUntil, InvalidValidUntil());\n require(!root.endorsed(user), EndorsedUserCannotBeUpdated());\n\n uint128 hookData = uint128(validUntil) << 64;\n hookData.setBit(FREEZE_BIT, isFrozen(token, user));\n IShareToken(token).setHookData(user, bytes16(hookData));\n\n emit UpdateMember(token, user, validUntil);\n }\n\n /// @inheritdoc IMemberlist\n function isMember(address token, address user) external view returns (bool isValid, uint64 validUntil) {\n validUntil = abi.encodePacked(IShareToken(token).hookDataOf(user)).toUint64(0);\n isValid = validUntil >= block.timestamp;\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-165\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC165\n function supportsInterface(bytes4 interfaceId) external pure override returns (bool) {\n return interfaceId == type(IHook).interfaceId || interfaceId == type(IERC165).interfaceId;\n }\n}\n" + }, + "src/hooks/interfaces/IFreezable.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\ninterface IFreezable {\n // --- Events ---\n event Freeze(address indexed token, address indexed user);\n event Unfreeze(address indexed token, address indexed user);\n\n // --- Errors ---\n error CannotFreezeZeroAddress();\n error EndorsedUserCannotBeFrozen();\n\n // --- Handling freezes ---\n /// @notice Freeze a user balance. Frozen users cannot receive nor send tokens\n function freeze(address token, address user) external;\n\n /// @notice Unfreeze a user balance\n function unfreeze(address token, address user) external;\n\n /// @notice Returns whether the user's tokens are frozen\n function isFrozen(address token, address user) external view returns (bool);\n}\n" + }, + "src/hooks/interfaces/IMemberlist.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\ninterface IMemberlist {\n // --- Events ---\n event UpdateMember(address indexed token, address indexed user, uint64 validUntil);\n\n // --- Errors ---\n error InvalidValidUntil();\n error EndorsedUserCannotBeUpdated();\n\n // --- Managing members ---\n /// @notice Add a member. Non-members cannot receive tokens, but can send tokens to valid members\n /// @param validUntil Timestamp until which the user will be a valid member\n function updateMember(address token, address user, uint64 validUntil) external;\n\n /// @notice Returns whether the user is a valid member of the token\n function isMember(address token, address user) external view returns (bool isValid, uint64 validUntil);\n}\n" + }, + "src/hub/Accounting.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\n\nimport {AccountId} from \"src/common/types/AccountId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {IAccounting, JournalEntry} from \"src/hub/interfaces/IAccounting.sol\";\nimport {TransientStorageLib} from \"src/misc/libraries/TransientStorageLib.sol\";\n\n/// @notice In a transaction there can be multiple journal entries for different pools,\n/// which can be interleaved. We want entries for the same pool to share the same journal ID.\n/// So we're keeping a journal ID per pool in transient storage.\nlibrary TransientJournal {\n function journalId(PoolId poolId) internal view returns (uint256) {\n return TransientStorageLib.tloadUint256(keccak256(abi.encode(\"journalId\", poolId)));\n }\n\n function setJournalId(PoolId poolId, uint256 value) internal {\n TransientStorageLib.tstore(keccak256(abi.encode(\"journalId\", poolId)), value);\n }\n}\n\n/// @title Accounting\n/// @notice Double-entry bookkeeping system.\n/// @dev To add entries, a specific pool needs to be unlocked.\n/// When locking, the debited and credited amounts need to match.\ncontract Accounting is Auth, IAccounting {\n mapping(PoolId => mapping(AccountId => Account)) public accounts;\n\n uint128 public transient debited;\n uint128 public transient credited;\n PoolId internal transient _currentPoolId;\n mapping(PoolId => uint64) internal _poolJournalIdCounter;\n\n constructor(address deployer) Auth(deployer) {}\n\n //----------------------------------------------------------------------------------------------\n // Lock/unlock\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IAccounting\n function unlock(PoolId poolId) external auth {\n require(PoolId.unwrap(_currentPoolId) == 0, AccountingAlreadyUnlocked());\n debited = 0;\n credited = 0;\n _currentPoolId = poolId;\n\n if (TransientJournal.journalId(poolId) == 0) {\n TransientJournal.setJournalId(poolId, _generateJournalId(poolId));\n }\n emit StartJournalId(poolId, TransientJournal.journalId(poolId));\n }\n\n /// @inheritdoc IAccounting\n function lock() external auth {\n require(debited == credited, Unbalanced());\n\n emit EndJournalId(_currentPoolId, TransientJournal.journalId(_currentPoolId));\n _currentPoolId = PoolId.wrap(0);\n }\n\n //----------------------------------------------------------------------------------------------\n // Account creation & metadata\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IAccounting\n function createAccount(PoolId poolId, AccountId account, bool isDebitNormal) external auth {\n require(accounts[poolId][account].lastUpdated == 0, AccountExists());\n accounts[poolId][account] = Account(0, 0, isDebitNormal, uint64(block.timestamp), \"\");\n emit CreateAccount(poolId, account, isDebitNormal);\n }\n\n /// @inheritdoc IAccounting\n function setAccountMetadata(PoolId poolId, AccountId account, bytes calldata metadata) external auth {\n require(accounts[poolId][account].lastUpdated != 0, AccountDoesNotExist());\n accounts[poolId][account].metadata = metadata;\n emit SetAccountMetadata(poolId, account, metadata);\n }\n \n //----------------------------------------------------------------------------------------------\n // Account updates\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IAccounting\n function addDebit(AccountId account, uint128 value) public auth {\n require(!_currentPoolId.isNull(), AccountingLocked());\n\n Account storage acc = accounts[_currentPoolId][account];\n require(acc.lastUpdated != 0, AccountDoesNotExist());\n\n acc.totalDebit += value;\n debited += value;\n acc.lastUpdated = uint64(block.timestamp);\n emit Debit(_currentPoolId, account, value);\n }\n\n /// @inheritdoc IAccounting\n function addCredit(AccountId account, uint128 value) public auth {\n require(!_currentPoolId.isNull(), AccountingLocked());\n\n Account storage acc = accounts[_currentPoolId][account];\n require(acc.lastUpdated != 0, AccountDoesNotExist());\n\n acc.totalCredit += value;\n credited += value;\n acc.lastUpdated = uint64(block.timestamp);\n emit Credit(_currentPoolId, account, value);\n }\n\n /// @inheritdoc IAccounting\n function addJournal(JournalEntry[] memory debits, JournalEntry[] memory credits) external auth {\n for (uint256 i; i < debits.length; i++) {\n addDebit(debits[i].accountId, debits[i].value);\n }\n\n for (uint256 i; i < credits.length; i++) {\n addCredit(credits[i].accountId, credits[i].value);\n }\n }\n\n //----------------------------------------------------------------------------------------------\n // View methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IAccounting\n function accountValue(PoolId poolId, AccountId account) external view returns (bool /* isPositive */, uint128) {\n Account storage acc = accounts[poolId][account];\n require(acc.lastUpdated != 0, AccountDoesNotExist());\n\n if (acc.isDebitNormal) {\n // For debit-normal accounts: Value = Total Debit - Total Credit\n if (acc.totalDebit >= acc.totalCredit) {\n return (true, acc.totalDebit - acc.totalCredit);\n } else {\n return (false, acc.totalCredit - acc.totalDebit);\n }\n } else {\n // For credit-normal accounts: Value = Total Credit - Total Debit\n if (acc.totalCredit >= acc.totalDebit) {\n return (true, acc.totalCredit - acc.totalDebit);\n } else {\n return (false, acc.totalDebit - acc.totalCredit);\n }\n }\n }\n\n /// @inheritdoc IAccounting\n function exists(PoolId poolId, AccountId account) external view returns (bool) {\n return accounts[poolId][account].lastUpdated != 0;\n }\n\n function _generateJournalId(PoolId poolId) internal returns (uint256) {\n return uint256((uint256(poolId.raw()) << 128) | ++_poolJournalIdCounter[poolId]);\n }\n}\n" + }, + "src/hub/Holdings.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IERC7726} from \"src/misc/interfaces/IERC7726.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {d18, D18} from \"src/misc/types/D18.sol\";\n\nimport {PricingLib} from \"src/common/libraries/PricingLib.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {AccountId} from \"src/common/types/AccountId.sol\";\nimport {IHoldings, Holding} from \"src/hub/interfaces/IHoldings.sol\";\nimport {IHubRegistry} from \"src/hub/interfaces/IHubRegistry.sol\";\nimport {IHoldings, Holding, HoldingAccount} from \"src/hub/interfaces/IHoldings.sol\";\n\n/// @title Holdings\n/// @notice Bookkeeping of the holdings and its associated accounting IDs for each pool.\ncontract Holdings is Auth, IHoldings {\n using MathLib for uint256;\n\n IHubRegistry public immutable hubRegistry;\n\n mapping(PoolId => mapping(ShareClassId => mapping(AssetId => Holding))) public holding;\n mapping(PoolId => mapping(ShareClassId => mapping(AssetId => mapping(uint8 kind => AccountId)))) public accountId;\n\n constructor(IHubRegistry hubRegistry_, address deployer) Auth(deployer) {\n hubRegistry = hubRegistry_;\n }\n\n //----------------------------------------------------------------------------------------------\n // Holding creation & updates\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHoldings\n function create(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n IERC7726 valuation_,\n bool isLiability_,\n HoldingAccount[] memory accounts\n ) external auth {\n require(!scId.isNull(), WrongShareClassId());\n require(address(valuation_) != address(0), WrongValuation());\n\n holding[poolId][scId][assetId] = Holding(0, 0, valuation_, isLiability_);\n\n for (uint256 i; i < accounts.length; i++) {\n accountId[poolId][scId][assetId][accounts[i].kind] = accounts[i].accountId;\n }\n\n emit Create(poolId, scId, assetId, valuation_, isLiability_, accounts);\n }\n\n /// @inheritdoc IHoldings\n function setAccountId(PoolId poolId, ShareClassId scId, AssetId assetId, uint8 kind, AccountId accountId_)\n external\n auth\n {\n Holding storage holding_ = holding[poolId][scId][assetId];\n require(address(holding_.valuation) != address(0), HoldingNotFound());\n\n accountId[poolId][scId][assetId][kind] = accountId_;\n\n emit SetAccountId(poolId, scId, assetId, kind, accountId_);\n }\n\n /// @inheritdoc IHoldings\n function updateValuation(PoolId poolId, ShareClassId scId, AssetId assetId, IERC7726 valuation_) external auth {\n require(address(valuation_) != address(0), WrongValuation());\n\n Holding storage holding_ = holding[poolId][scId][assetId];\n require(address(holding_.valuation) != address(0), HoldingNotFound());\n\n holding_.valuation = valuation_;\n\n emit UpdateValuation(poolId, scId, assetId, valuation_);\n }\n\n //----------------------------------------------------------------------------------------------\n // Value updates\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHoldings\n function increase(PoolId poolId, ShareClassId scId, AssetId assetId, D18 pricePoolPerAsset, uint128 amount_)\n external\n auth\n returns (uint128 amountValue)\n {\n Holding storage holding_ = holding[poolId][scId][assetId];\n require(address(holding_.valuation) != address(0), HoldingNotFound());\n\n amountValue = PricingLib.convertWithPrice(\n amount_, hubRegistry.decimals(assetId), hubRegistry.decimals(poolId), pricePoolPerAsset\n ).toUint128();\n\n holding_.assetAmount += amount_;\n holding_.assetAmountValue += amountValue;\n\n emit Increase(poolId, scId, assetId, pricePoolPerAsset, amount_, amountValue);\n }\n\n /// @inheritdoc IHoldings\n function decrease(PoolId poolId, ShareClassId scId, AssetId assetId, D18 pricePoolPerAsset, uint128 amount_)\n external\n auth\n returns (uint128 amountValue)\n {\n Holding storage holding_ = holding[poolId][scId][assetId];\n require(address(holding_.valuation) != address(0), HoldingNotFound());\n\n amountValue = PricingLib.convertWithPrice(\n amount_, hubRegistry.decimals(assetId), hubRegistry.decimals(poolId), pricePoolPerAsset\n ).toUint128();\n\n holding_.assetAmount -= amount_;\n holding_.assetAmountValue -= amountValue;\n\n emit Decrease(poolId, scId, assetId, pricePoolPerAsset, amount_, amountValue);\n }\n\n /// @inheritdoc IHoldings\n function update(PoolId poolId, ShareClassId scId, AssetId assetId)\n external\n auth\n returns (bool isPositive, uint128 diffValue)\n {\n Holding storage holding_ = holding[poolId][scId][assetId];\n require(address(holding_.valuation) != address(0), HoldingNotFound());\n\n uint128 currentAmountValue = holding_.valuation.getQuote(\n holding_.assetAmount, assetId.addr(), hubRegistry.currency(poolId).addr()\n ).toUint128();\n\n isPositive = currentAmountValue >= holding_.assetAmountValue;\n diffValue =\n isPositive ? currentAmountValue - holding_.assetAmountValue : holding_.assetAmountValue - currentAmountValue;\n\n holding_.assetAmountValue = currentAmountValue;\n\n emit Update(poolId, scId, assetId, isPositive, diffValue);\n }\n\n //----------------------------------------------------------------------------------------------\n // View methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHoldings\n function value(PoolId poolId, ShareClassId scId, AssetId assetId) external view returns (uint128 value_) {\n Holding storage holding_ = holding[poolId][scId][assetId];\n require(address(holding_.valuation) != address(0), HoldingNotFound());\n\n return holding_.assetAmountValue;\n }\n\n /// @inheritdoc IHoldings\n function amount(PoolId poolId, ShareClassId scId, AssetId assetId) external view returns (uint128 amount_) {\n Holding storage holding_ = holding[poolId][scId][assetId];\n require(address(holding_.valuation) != address(0), HoldingNotFound());\n\n return holding_.assetAmount;\n }\n\n /// @inheritdoc IHoldings\n function valuation(PoolId poolId, ShareClassId scId, AssetId assetId) external view returns (IERC7726) {\n Holding storage holding_ = holding[poolId][scId][assetId];\n require(address(holding_.valuation) != address(0), HoldingNotFound());\n\n return holding_.valuation;\n }\n\n /// @inheritdoc IHoldings\n function isLiability(PoolId poolId, ShareClassId scId, AssetId assetId) external view returns (bool) {\n Holding storage holding_ = holding[poolId][scId][assetId];\n require(address(holding_.valuation) != address(0), HoldingNotFound());\n\n return holding_.isLiability;\n }\n\n /// @inheritdoc IHoldings\n function exists(PoolId poolId, ShareClassId scId, AssetId assetId) external view returns (bool) {\n return address(holding[poolId][scId][assetId].valuation) != address(0);\n }\n}\n" + }, + "src/hub/Hub.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {D18, d18} from \"src/misc/types/D18.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {IERC7726} from \"src/misc/interfaces/IERC7726.sol\";\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {Multicall, IMulticall} from \"src/misc/Multicall.sol\";\nimport {Recoverable} from \"src/misc/Recoverable.sol\";\n\nimport {IGateway} from \"src/common/interfaces/IGateway.sol\";\nimport {IHubGatewayHandler} from \"src/common/interfaces/IGatewayHandlers.sol\";\nimport {IPoolMessageSender} from \"src/common/interfaces/IGatewaySenders.sol\";\nimport {IHubGuardianActions} from \"src/common/interfaces/IGuardianActions.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {AccountId} from \"src/common/types/AccountId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\n\nimport {IAccounting, JournalEntry} from \"src/hub/interfaces/IAccounting.sol\";\nimport {IHubRegistry} from \"src/hub/interfaces/IHubRegistry.sol\";\nimport {IShareClassManager} from \"src/hub/interfaces/IShareClassManager.sol\";\nimport {IHoldings, HoldingAccount} from \"src/hub/interfaces/IHoldings.sol\";\nimport {IHub, AccountType} from \"src/hub/interfaces/IHub.sol\";\n\n/// @title Hub\n/// @notice Central pool management contract, that brings together all functions in one place.\n/// Pools can assign hub managers which have full rights over all actions.\n///\n/// Also acts as the central contract that routes messages from other chains to the Hub contracts.\ncontract Hub is Multicall, Auth, Recoverable, IHub, IHubGatewayHandler, IHubGuardianActions {\n using MathLib for uint256;\n\n IHubRegistry public immutable hubRegistry;\n\n IGateway public gateway;\n IHoldings public holdings;\n IAccounting public accounting;\n IPoolMessageSender public sender;\n IShareClassManager public shareClassManager;\n\n constructor(\n IShareClassManager shareClassManager_,\n IHubRegistry hubRegistry_,\n IAccounting accounting_,\n IHoldings holdings_,\n IGateway gateway_,\n address deployer\n ) Auth(deployer) {\n shareClassManager = shareClassManager_;\n hubRegistry = hubRegistry_;\n accounting = accounting_;\n holdings = holdings_;\n gateway = gateway_;\n }\n\n //----------------------------------------------------------------------------------------------\n // System methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHub\n function file(bytes32 what, address data) external {\n _auth();\n\n if (what == \"sender\") sender = IPoolMessageSender(data);\n else if (what == \"holdings\") holdings = IHoldings(data);\n else if (what == \"accounting\") accounting = IAccounting(data);\n else if (what == \"shareClassManager\") shareClassManager = IShareClassManager(data);\n else if (what == \"gateway\") gateway = IGateway(data);\n else revert FileUnrecognizedParam();\n\n emit File(what, data);\n }\n\n /// @inheritdoc IMulticall\n /// @notice performs a multicall but all messages sent in the process will be batched\n function multicall(bytes[] calldata data) public payable override {\n bool wasBatching = gateway.isBatching();\n if (!wasBatching) {\n gateway.startBatching();\n gateway.payTransaction{value: msg.value}(msg.sender);\n }\n\n super.multicall(data);\n\n if (!wasBatching) {\n gateway.endBatching();\n }\n }\n\n /// @inheritdoc IHubGuardianActions\n function createPool(PoolId poolId, address admin, AssetId currency) external payable {\n _auth();\n\n require(poolId.centrifugeId() == sender.localCentrifugeId(), InvalidPoolId());\n hubRegistry.registerPool(poolId, admin, currency);\n }\n\n //----------------------------------------------------------------------------------------------\n // Permissionless methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHub\n function notifyDeposit(PoolId poolId, ShareClassId scId, AssetId assetId, bytes32 investor, uint32 maxClaims)\n external\n payable\n {\n _pay();\n\n uint128 totalPayoutShareAmount;\n uint128 totalPaymentAssetAmount;\n uint128 cancelledAssetAmount;\n\n for (uint32 i = 0; i < maxClaims; i++) {\n (uint128 payoutShareAmount, uint128 paymentAssetAmount, uint128 cancelled, bool canClaimAgain) =\n shareClassManager.claimDeposit(poolId, scId, investor, assetId);\n\n totalPayoutShareAmount += payoutShareAmount;\n totalPaymentAssetAmount += paymentAssetAmount;\n\n // Should be written at most once with non-zero amount iff the last claimable epoch was processed and\n // the user had a pending cancellation\n // NOTE: Purposely delaying corresponding message dispatch after deposit fulfillment message\n if (cancelled > 0) {\n cancelledAssetAmount = cancelled;\n }\n\n if (!canClaimAgain) {\n break;\n }\n }\n\n sender.sendFulfilledDepositRequest(\n poolId, scId, assetId, investor, totalPaymentAssetAmount, totalPayoutShareAmount\n );\n\n // If cancellation was queued, notify about delayed cancellation\n if (cancelledAssetAmount > 0) {\n sender.sendFulfilledCancelDepositRequest(poolId, scId, assetId, investor, cancelledAssetAmount);\n }\n }\n\n /// @inheritdoc IHub\n function notifyRedeem(PoolId poolId, ShareClassId scId, AssetId assetId, bytes32 investor, uint32 maxClaims)\n external\n payable\n {\n _pay();\n\n uint128 totalPayoutAssetAmount;\n uint128 totalPaymentShareAmount;\n uint128 cancelledShareAmount;\n\n for (uint32 i = 0; i < maxClaims; i++) {\n (uint128 payoutAssetAmount, uint128 paymentShareAmount, uint128 cancelled, bool canClaimAgain) =\n shareClassManager.claimRedeem(poolId, scId, investor, assetId);\n\n totalPayoutAssetAmount += payoutAssetAmount;\n totalPaymentShareAmount += paymentShareAmount;\n\n // Should be written at most once with non-zero amount iff the last claimable epoch was processed and\n // the user had a pending cancellation\n // NOTE: Purposely delaying corresponding message dispatch after redemption fulfillment message\n if (cancelled > 0) {\n cancelledShareAmount = cancelled;\n }\n\n if (!canClaimAgain) {\n break;\n }\n }\n\n sender.sendFulfilledRedeemRequest(\n poolId, scId, assetId, investor, totalPayoutAssetAmount, totalPaymentShareAmount\n );\n\n // If cancellation was queued, notify about delayed cancellation\n if (cancelledShareAmount > 0) {\n sender.sendFulfilledCancelRedeemRequest(poolId, scId, assetId, investor, cancelledShareAmount);\n }\n }\n\n //----------------------------------------------------------------------------------------------\n // Pool admin methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHub\n function notifyPool(PoolId poolId, uint16 centrifugeId) external payable {\n _isManagerAndPaid(poolId);\n\n emit NotifyPool(centrifugeId, poolId);\n sender.sendNotifyPool(centrifugeId, poolId);\n }\n\n /// @inheritdoc IHub\n function notifyShareClass(PoolId poolId, ShareClassId scId, uint16 centrifugeId, bytes32 hook) external payable {\n _isManagerAndPaid(poolId);\n\n require(shareClassManager.exists(poolId, scId), IShareClassManager.ShareClassNotFound());\n\n (string memory name, string memory symbol, bytes32 salt) = shareClassManager.metadata(scId);\n uint8 decimals = hubRegistry.decimals(poolId);\n\n emit NotifyShareClass(centrifugeId, poolId, scId);\n sender.sendNotifyShareClass(centrifugeId, poolId, scId, name, symbol, decimals, salt, hook);\n }\n\n /// @inheritdoc IHub\n function notifyShareMetadata(PoolId poolId, ShareClassId scId, uint16 centrifugeId) public payable {\n _isManagerAndPaid(poolId);\n\n (string memory name, string memory symbol,) = shareClassManager.metadata(scId);\n\n emit NotifyShareMetadata(centrifugeId, poolId, scId, name, symbol);\n sender.sendNotifyShareMetadata(centrifugeId, poolId, scId, name, symbol);\n }\n\n /// @inheritdoc IHub\n function updateShareHook(PoolId poolId, ShareClassId scId, uint16 centrifugeId, bytes32 hook) public payable {\n _isManagerAndPaid(poolId);\n\n emit UpdateShareHook(centrifugeId, poolId, scId, hook);\n sender.sendUpdateShareHook(centrifugeId, poolId, scId, hook);\n }\n\n /// @inheritdoc IHub\n function notifySharePrice(PoolId poolId, ShareClassId scId, uint16 centrifugeId) public payable {\n _isManagerAndPaid(poolId);\n\n (, D18 poolPerShare) = shareClassManager.metrics(scId);\n\n emit NotifySharePrice(centrifugeId, poolId, scId, poolPerShare);\n sender.sendNotifyPricePoolPerShare(centrifugeId, poolId, scId, poolPerShare);\n }\n\n /// @inheritdoc IHub\n function notifyAssetPrice(PoolId poolId, ShareClassId scId, AssetId assetId) public payable {\n _isManagerAndPaid(poolId);\n D18 pricePoolPerAsset = _pricePoolPerAsset(poolId, scId, assetId);\n emit NotifyAssetPrice(assetId.centrifugeId(), poolId, scId, assetId, pricePoolPerAsset);\n sender.sendNotifyPricePoolPerAsset(poolId, scId, assetId, pricePoolPerAsset);\n }\n\n /// @inheritdoc IHub\n function triggerIssueShares(uint16 centrifugeId, PoolId poolId, ShareClassId scId, address who, uint128 shares)\n public\n payable\n {\n _isManagerAndPaid(poolId);\n\n sender.sendTriggerIssueShares(centrifugeId, poolId, scId, who, shares);\n }\n\n /// @inheritdoc IHub\n function triggerSubmitQueuedShares(uint16 centrifugeId, PoolId poolId, ShareClassId scId) public payable {\n _isManagerAndPaid(poolId);\n\n sender.sendTriggerSubmitQueuedShares(centrifugeId, poolId, scId);\n }\n\n /// @inheritdoc IHub\n function triggerSubmitQueuedAssets(PoolId poolId, ShareClassId scId, AssetId assetId) public payable {\n _isManagerAndPaid(poolId);\n\n sender.sendTriggerSubmitQueuedAssets(poolId, scId, assetId);\n }\n\n /// @inheritdoc IHub\n function setQueue(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bool enabled) public payable {\n _isManagerAndPaid(poolId);\n\n sender.sendSetQueue(centrifugeId, poolId, scId, enabled);\n }\n\n /// @inheritdoc IHub\n function setPoolMetadata(PoolId poolId, bytes calldata metadata) external payable {\n _isManager(poolId);\n\n hubRegistry.setMetadata(poolId, metadata);\n }\n\n /// @inheritdoc IHub\n function updateShareClassMetadata(PoolId poolId, ShareClassId scId, string calldata name, string calldata symbol)\n external\n payable\n {\n _isManager(poolId);\n\n shareClassManager.updateMetadata(poolId, scId, name, symbol);\n }\n\n /// @inheritdoc IHub\n function updateManager(PoolId poolId, address who, bool canManage) external payable {\n _isManager(poolId);\n\n hubRegistry.updateManager(poolId, who, canManage);\n }\n\n /// @inheritdoc IHub\n function addShareClass(PoolId poolId, string calldata name, string calldata symbol, bytes32 salt)\n external\n payable\n returns (ShareClassId scId)\n {\n _isManager(poolId);\n\n return shareClassManager.addShareClass(poolId, name, symbol, salt);\n }\n\n /// @inheritdoc IHub\n function approveDeposits(\n PoolId poolId,\n ShareClassId scId,\n AssetId depositAssetId,\n uint32 nowDepositEpochId,\n uint128 approvedAssetAmount\n ) external payable returns (uint128 pendingAssetAmount, uint128 approvedPoolAmount) {\n _isManagerAndPaid(poolId);\n D18 pricePoolPerAsset = _pricePoolPerAsset(poolId, scId, depositAssetId);\n (pendingAssetAmount, approvedPoolAmount) = shareClassManager.approveDeposits(\n poolId, scId, depositAssetId, nowDepositEpochId, approvedAssetAmount, pricePoolPerAsset\n );\n\n sender.sendApprovedDeposits(poolId, scId, depositAssetId, approvedAssetAmount, pricePoolPerAsset);\n }\n\n /// @inheritdoc IHub\n function approveRedeems(\n PoolId poolId,\n ShareClassId scId,\n AssetId payoutAssetId,\n uint32 nowRedeemEpochId,\n uint128 approvedShareAmount\n ) external payable returns (uint128 pendingShareAmount) {\n _isManager(poolId);\n\n D18 price = _pricePoolPerAsset(poolId, scId, payoutAssetId);\n (pendingShareAmount) =\n shareClassManager.approveRedeems(poolId, scId, payoutAssetId, nowRedeemEpochId, approvedShareAmount, price);\n }\n\n /// @inheritdoc IHub\n function issueShares(\n PoolId poolId,\n ShareClassId scId,\n AssetId depositAssetId,\n uint32 nowIssueEpochId,\n D18 navPoolPerShare\n ) external payable returns (uint128 issuedShareAmount, uint128 depositAssetAmount, uint128 depositPoolAmount) {\n _isManagerAndPaid(poolId);\n\n (issuedShareAmount, depositAssetAmount, depositPoolAmount) =\n shareClassManager.issueShares(poolId, scId, depositAssetId, nowIssueEpochId, navPoolPerShare);\n\n sender.sendIssuedShares(poolId, scId, depositAssetId, issuedShareAmount, navPoolPerShare);\n }\n\n /// @inheritdoc IHub\n function revokeShares(\n PoolId poolId,\n ShareClassId scId,\n AssetId payoutAssetId,\n uint32 nowRevokeEpochId,\n D18 navPoolPerShare\n ) external payable returns (uint128 revokedShareAmount, uint128 payoutAssetAmount, uint128 payoutPoolAmount) {\n _isManagerAndPaid(poolId);\n\n (revokedShareAmount, payoutAssetAmount, payoutPoolAmount) =\n shareClassManager.revokeShares(poolId, scId, payoutAssetId, nowRevokeEpochId, navPoolPerShare);\n\n sender.sendRevokedShares(poolId, scId, payoutAssetId, payoutAssetAmount, revokedShareAmount, navPoolPerShare);\n }\n\n /// @inheritdoc IHub\n function updateRestriction(PoolId poolId, ShareClassId scId, uint16 centrifugeId, bytes calldata payload)\n external\n payable\n {\n _isManagerAndPaid(poolId);\n\n require(shareClassManager.exists(poolId, scId), IShareClassManager.ShareClassNotFound());\n\n emit UpdateRestriction(centrifugeId, poolId, scId, payload);\n sender.sendUpdateRestriction(centrifugeId, poolId, scId, payload);\n }\n\n /// @inheritdoc IHub\n function updateContract(\n PoolId poolId,\n ShareClassId scId,\n uint16 centrifugeId,\n bytes32 target,\n bytes calldata payload\n ) external payable {\n _isManagerAndPaid(poolId);\n\n require(shareClassManager.exists(poolId, scId), IShareClassManager.ShareClassNotFound());\n\n emit UpdateContract(centrifugeId, poolId, scId, target, payload);\n sender.sendUpdateContract(centrifugeId, poolId, scId, target, payload);\n }\n\n /// @inheritdoc IHub\n function updatePricePerShare(PoolId poolId, ShareClassId scId, D18 navPoolPerShare) public payable {\n _isManager(poolId);\n\n shareClassManager.updatePricePerShare(poolId, scId, navPoolPerShare);\n }\n\n /// @inheritdoc IHub\n function createHolding(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n IERC7726 valuation,\n AccountId assetAccount,\n AccountId equityAccount,\n AccountId gainAccount,\n AccountId lossAccount\n ) external payable {\n _isManager(poolId);\n\n require(hubRegistry.isRegistered(assetId), IHubRegistry.AssetNotFound());\n require(\n accounting.exists(poolId, assetAccount) && accounting.exists(poolId, equityAccount)\n && accounting.exists(poolId, lossAccount) && accounting.exists(poolId, gainAccount),\n IAccounting.AccountDoesNotExist()\n );\n\n HoldingAccount[] memory accounts = new HoldingAccount[](4);\n accounts[0] = HoldingAccount(assetAccount, uint8(AccountType.Asset));\n accounts[1] = HoldingAccount(equityAccount, uint8(AccountType.Equity));\n accounts[3] = HoldingAccount(gainAccount, uint8(AccountType.Gain));\n accounts[2] = HoldingAccount(lossAccount, uint8(AccountType.Loss));\n\n holdings.create(poolId, scId, assetId, valuation, false, accounts);\n }\n\n /// @inheritdoc IHub\n function createLiability(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n IERC7726 valuation,\n AccountId expenseAccount,\n AccountId liabilityAccount\n ) external payable {\n _isManager(poolId);\n\n require(hubRegistry.isRegistered(assetId), IHubRegistry.AssetNotFound());\n require(\n accounting.exists(poolId, expenseAccount) && accounting.exists(poolId, liabilityAccount),\n IAccounting.AccountDoesNotExist()\n );\n\n HoldingAccount[] memory accounts = new HoldingAccount[](2);\n accounts[0] = HoldingAccount(expenseAccount, uint8(AccountType.Expense));\n accounts[1] = HoldingAccount(liabilityAccount, uint8(AccountType.Liability));\n\n holdings.create(poolId, scId, assetId, valuation, true, accounts);\n }\n\n /// @inheritdoc IHub\n function updateHoldingValue(PoolId poolId, ShareClassId scId, AssetId assetId) public payable {\n _isManager(poolId);\n\n accounting.unlock(poolId);\n\n (bool isPositive, uint128 diff) = holdings.update(poolId, scId, assetId);\n\n // Save a diff=0 update gas cost\n if (isPositive && diff > 0) {\n if (holdings.isLiability(poolId, scId, assetId)) {\n accounting.addCredit(holdings.accountId(poolId, scId, assetId, uint8(AccountType.Liability)), diff);\n accounting.addDebit(holdings.accountId(poolId, scId, assetId, uint8(AccountType.Expense)), diff);\n } else {\n accounting.addCredit(holdings.accountId(poolId, scId, assetId, uint8(AccountType.Gain)), diff);\n accounting.addDebit(holdings.accountId(poolId, scId, assetId, uint8(AccountType.Asset)), diff);\n }\n } else if (diff > 0) {\n if (holdings.isLiability(poolId, scId, assetId)) {\n accounting.addCredit(holdings.accountId(poolId, scId, assetId, uint8(AccountType.Expense)), diff);\n accounting.addDebit(holdings.accountId(poolId, scId, assetId, uint8(AccountType.Liability)), diff);\n } else {\n accounting.addCredit(holdings.accountId(poolId, scId, assetId, uint8(AccountType.Asset)), diff);\n accounting.addDebit(holdings.accountId(poolId, scId, assetId, uint8(AccountType.Loss)), diff);\n }\n }\n\n accounting.lock();\n }\n\n /// @inheritdoc IHub\n function updateHoldingValuation(PoolId poolId, ShareClassId scId, AssetId assetId, IERC7726 valuation)\n external\n payable\n {\n _isManager(poolId);\n\n holdings.updateValuation(poolId, scId, assetId, valuation);\n }\n\n /// @inheritdoc IHub\n function setHoldingAccountId(PoolId poolId, ShareClassId scId, AssetId assetId, uint8 kind, AccountId accountId)\n external\n payable\n {\n _isManager(poolId);\n\n holdings.setAccountId(poolId, scId, assetId, kind, accountId);\n }\n\n /// @inheritdoc IHub\n function createAccount(PoolId poolId, AccountId account, bool isDebitNormal) public payable {\n _isManager(poolId);\n\n accounting.createAccount(poolId, account, isDebitNormal);\n }\n\n /// @inheritdoc IHub\n function setAccountMetadata(PoolId poolId, AccountId account, bytes calldata metadata) external payable {\n _isManager(poolId);\n\n accounting.setAccountMetadata(poolId, account, metadata);\n }\n\n /// @inheritdoc IHub\n function updateJournal(PoolId poolId, JournalEntry[] memory debits, JournalEntry[] memory credits) external {\n _isManager(poolId);\n\n accounting.unlock(poolId);\n accounting.addJournal(debits, credits);\n accounting.lock();\n }\n\n //----------------------------------------------------------------------------------------------\n // Gateway owner methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHubGatewayHandler\n function registerAsset(AssetId assetId, uint8 decimals) external {\n _auth();\n\n hubRegistry.registerAsset(assetId, decimals);\n }\n\n /// @inheritdoc IHubGatewayHandler\n function depositRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId depositAssetId, uint128 amount)\n external\n {\n _auth();\n\n shareClassManager.requestDeposit(poolId, scId, amount, investor, depositAssetId);\n }\n\n /// @inheritdoc IHubGatewayHandler\n function redeemRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId payoutAssetId, uint128 amount)\n external\n {\n _auth();\n\n shareClassManager.requestRedeem(poolId, scId, amount, investor, payoutAssetId);\n }\n\n /// @inheritdoc IHubGatewayHandler\n function cancelDepositRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId depositAssetId)\n external\n {\n _auth();\n\n uint128 cancelledAssetAmount = shareClassManager.cancelDepositRequest(poolId, scId, investor, depositAssetId);\n\n // Cancellation might have been queued such that it will be executed in the future during claiming\n if (cancelledAssetAmount > 0) {\n sender.sendFulfilledCancelDepositRequest(poolId, scId, depositAssetId, investor, cancelledAssetAmount);\n }\n }\n\n /// @inheritdoc IHubGatewayHandler\n function cancelRedeemRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId payoutAssetId) external {\n _auth();\n\n uint128 cancelledShareAmount = shareClassManager.cancelRedeemRequest(poolId, scId, investor, payoutAssetId);\n\n // Cancellation might have been queued such that it will be executed in the future during claiming\n if (cancelledShareAmount > 0) {\n sender.sendFulfilledCancelRedeemRequest(poolId, scId, payoutAssetId, investor, cancelledShareAmount);\n }\n }\n\n /// @inheritdoc IHubGatewayHandler\n function updateHoldingAmount(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n uint128 amount,\n D18 pricePoolPerAsset,\n bool isIncrease\n ) external {\n _auth();\n\n accounting.unlock(poolId);\n\n bool isLiability = holdings.isLiability(poolId, scId, assetId);\n AccountType debitAccountType = isLiability ? AccountType.Expense : AccountType.Asset;\n AccountType creditAccountType = isLiability ? AccountType.Liability : AccountType.Equity;\n\n if (isIncrease) {\n uint128 value = holdings.increase(poolId, scId, assetId, pricePoolPerAsset, amount);\n accounting.addDebit(holdings.accountId(poolId, scId, assetId, uint8(debitAccountType)), value);\n accounting.addCredit(holdings.accountId(poolId, scId, assetId, uint8(creditAccountType)), value);\n } else {\n uint128 value = holdings.decrease(poolId, scId, assetId, pricePoolPerAsset, amount);\n accounting.addDebit(holdings.accountId(poolId, scId, assetId, uint8(creditAccountType)), value);\n accounting.addCredit(holdings.accountId(poolId, scId, assetId, uint8(debitAccountType)), value);\n }\n\n accounting.lock();\n }\n\n /// @inheritdoc IHubGatewayHandler\n function increaseShareIssuance(PoolId poolId, ShareClassId scId, uint128 amount) external {\n _auth();\n\n shareClassManager.increaseShareClassIssuance(poolId, scId, amount);\n }\n\n /// @inheritdoc IHubGatewayHandler\n function decreaseShareIssuance(PoolId poolId, ShareClassId scId, uint128 amount) external {\n _auth();\n\n shareClassManager.decreaseShareClassIssuance(poolId, scId, amount);\n }\n\n //----------------------------------------------------------------------------------------------\n // Internal methods\n //----------------------------------------------------------------------------------------------\n\n /// @dev Ensure the sender is authorized\n function _auth() internal auth {}\n\n /// @dev Ensure the method can be used without reentrancy issues, and the sender is a pool admin\n function _isManager(PoolId poolId) internal protected {\n require(hubRegistry.manager(poolId, msg.sender), IHub.NotManager());\n }\n\n /// @dev Ensure the sender is authorized\n function _isManagerAndPaid(PoolId poolId) internal {\n _isManager(poolId);\n _pay();\n }\n\n /// @notice Send native tokens to the gateway for transaction payment if it's not in a multicall.\n function _pay() internal {\n if (!gateway.isBatching()) {\n gateway.payTransaction{value: msg.value}(msg.sender);\n }\n }\n\n function _pricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId) internal view returns (D18) {\n AssetId poolCurrency = hubRegistry.currency(poolId);\n // NOTE: We assume symmetric prices are provided by holdings valuation\n IERC7726 valuation = holdings.valuation(poolId, scId, assetId);\n\n // Retrieve amount of 1 asset unit in pool currency\n uint128 assetUnitAmount = (10 ** hubRegistry.decimals(assetId.raw())).toUint128();\n uint128 poolUnitAmount = (10 ** hubRegistry.decimals(poolCurrency.raw())).toUint128();\n uint128 poolAmountPerAsset =\n valuation.getQuote(assetUnitAmount, assetId.addr(), poolCurrency.addr()).toUint128();\n\n // Retrieve price by normalizing by pool denomination\n return d18(poolAmountPerAsset, poolUnitAmount);\n }\n}\n" + }, + "src/hub/HubRegistry.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {IERC6909Decimals} from \"src/misc/interfaces/IERC6909.sol\";\n\nimport {PoolId, newPoolId} from \"src/common/types/PoolId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {IHubRegistry} from \"src/hub/interfaces/IHubRegistry.sol\";\n\n/// @title Hub Registry\n/// @notice Registry of all known pools, currencies, and assets.\ncontract HubRegistry is Auth, IHubRegistry {\n using MathLib for uint256;\n\n mapping(AssetId => uint8) internal _decimals;\n\n mapping(PoolId => bytes) public metadata;\n mapping(PoolId => AssetId) public currency;\n mapping(bytes32 => address) public dependency;\n mapping(PoolId => mapping(address => bool)) public manager;\n\n constructor(address deployer) Auth(deployer) {}\n\n //----------------------------------------------------------------------------------------------\n // Registration methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHubRegistry\n function registerAsset(AssetId assetId, uint8 decimals_) external auth {\n require(_decimals[assetId] == 0, AssetAlreadyRegistered());\n\n _decimals[assetId] = decimals_;\n\n emit NewAsset(assetId, decimals_);\n }\n\n /// @inheritdoc IHubRegistry\n function registerPool(PoolId poolId_, address manager_, AssetId currency_) external auth {\n require(manager_ != address(0), EmptyAccount());\n require(!currency_.isNull(), EmptyCurrency());\n require(currency[poolId_].isNull(), PoolAlreadyRegistered());\n\n manager[poolId_][manager_] = true;\n currency[poolId_] = currency_;\n\n emit NewPool(poolId_, manager_, currency_);\n }\n\n //----------------------------------------------------------------------------------------------\n // Update methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHubRegistry\n function updateManager(PoolId poolId_, address manager_, bool canManage) external auth {\n require(exists(poolId_), NonExistingPool(poolId_));\n require(manager_ != address(0), EmptyAccount());\n\n manager[poolId_][manager_] = canManage;\n\n emit UpdateManager(poolId_, manager_, canManage);\n }\n\n /// @inheritdoc IHubRegistry\n function setMetadata(PoolId poolId_, bytes calldata metadata_) external auth {\n require(exists(poolId_), NonExistingPool(poolId_));\n\n metadata[poolId_] = metadata_;\n\n emit SetMetadata(poolId_, metadata_);\n }\n\n /// @inheritdoc IHubRegistry\n function updateDependency(bytes32 what, address dependency_) external auth {\n dependency[what] = dependency_;\n\n emit UpdateDependency(what, dependency_);\n }\n\n /// @inheritdoc IHubRegistry\n function updateCurrency(PoolId poolId_, AssetId currency_) external auth {\n require(exists(poolId_), NonExistingPool(poolId_));\n require(!currency_.isNull(), EmptyCurrency());\n\n currency[poolId_] = currency_;\n\n emit UpdateCurrency(poolId_, currency_);\n }\n\n //----------------------------------------------------------------------------------------------\n // View methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHubRegistry\n function poolId(uint16 centrifugeId, uint48 postfix) public pure returns (PoolId poolId_) {\n poolId_ = newPoolId(centrifugeId, postfix);\n }\n\n /// @inheritdoc IHubRegistry\n function decimals(AssetId assetId) public view returns (uint8 decimals_) {\n decimals_ = _decimals[assetId];\n require(decimals_ > 0, AssetNotFound());\n }\n\n /// @inheritdoc IHubRegistry\n function decimals(PoolId poolId_) public view returns (uint8 decimals_) {\n decimals_ = _decimals[currency[poolId_]];\n require(decimals_ > 0, AssetNotFound());\n }\n\n /// @inheritdoc IERC6909Decimals\n function decimals(uint256 asset_) external view returns (uint8 decimals_) {\n decimals_ = _decimals[AssetId.wrap(asset_.toUint128())];\n require(decimals_ > 0, AssetNotFound());\n }\n\n /// @inheritdoc IHubRegistry\n function exists(PoolId poolId_) public view returns (bool) {\n return !currency[poolId_].isNull();\n }\n\n /// @inheritdoc IHubRegistry\n function isRegistered(AssetId assetId) public view returns (bool) {\n return _decimals[assetId] != 0;\n }\n}\n" + }, + "src/hub/ShareClassManager.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {D18, d18} from \"src/misc/types/D18.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {ShareClassId, newShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {PricingLib} from \"src/common/libraries/PricingLib.sol\";\n\nimport {IHubRegistry} from \"src/hub/interfaces/IHubRegistry.sol\";\nimport {\n IShareClassManager,\n EpochInvestAmounts,\n EpochRedeemAmounts,\n UserOrder,\n ShareClassMetadata,\n ShareClassMetrics,\n QueuedOrder,\n RequestType,\n EpochId\n} from \"src/hub/interfaces/IShareClassManager.sol\";\n\n/// @title Share Class Manager\n/// @notice Manager for the share classes of a pool, and the core logic for tracking, approving, and fulfilling\n/// requests.\ncontract ShareClassManager is Auth, IShareClassManager {\n using MathLib for *;\n using CastLib for *;\n using BytesLib for bytes;\n\n IHubRegistry public immutable hubRegistry;\n\n // Share classes\n mapping(bytes32 salt => bool) public salts;\n mapping(PoolId poolId => uint32) public shareClassCount;\n mapping(ShareClassId scId => ShareClassMetrics) public metrics;\n mapping(ShareClassId scId => ShareClassMetadata) public metadata;\n mapping(PoolId poolId => mapping(ShareClassId => bool)) public shareClassIds;\n\n // Epochs\n mapping(ShareClassId scId => mapping(AssetId assetId => EpochId)) public epochId;\n mapping(ShareClassId scId => mapping(AssetId assetId => mapping(uint32 epochId_ => EpochInvestAmounts epoch)))\n public epochInvestAmounts;\n mapping(ShareClassId scId => mapping(AssetId assetId => mapping(uint32 epochId_ => EpochRedeemAmounts epoch)))\n public epochRedeemAmounts;\n\n // Pending requests\n mapping(ShareClassId scId => mapping(AssetId payoutAssetId => uint128 pending)) public pendingRedeem;\n mapping(ShareClassId scId => mapping(AssetId depositAssetId => uint128 pending)) public pendingDeposit;\n mapping(ShareClassId scId => mapping(AssetId payoutAssetId => mapping(bytes32 investor => UserOrder pending)))\n public redeemRequest;\n mapping(ShareClassId scId => mapping(AssetId depositAssetId => mapping(bytes32 investor => UserOrder pending)))\n public depositRequest;\n\n // Queued requests\n mapping(ShareClassId scId => mapping(AssetId payoutAssetId => mapping(bytes32 investor => QueuedOrder queued)))\n public queuedRedeemRequest;\n mapping(ShareClassId scId => mapping(AssetId depositAssetId => mapping(bytes32 investor => QueuedOrder queued)))\n public queuedDepositRequest;\n\n constructor(IHubRegistry hubRegistry_, address deployer) Auth(deployer) {\n hubRegistry = hubRegistry_;\n }\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IShareClassManager\n function addShareClass(PoolId poolId, string calldata name, string calldata symbol, bytes32 salt)\n external\n auth\n returns (ShareClassId scId_)\n {\n scId_ = previewNextShareClassId(poolId);\n\n uint32 index = ++shareClassCount[poolId];\n shareClassIds[poolId][scId_] = true;\n\n _updateMetadata(scId_, name, symbol, salt);\n\n emit AddShareClass(poolId, scId_, index, name, symbol, salt);\n }\n\n //----------------------------------------------------------------------------------------------\n // Incoming requests\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IShareClassManager\n function requestDeposit(PoolId poolId, ShareClassId scId_, uint128 amount, bytes32 investor, AssetId depositAssetId)\n external\n auth\n {\n require(exists(poolId, scId_), ShareClassNotFound());\n\n // NOTE: CV ensures amount > 0\n _updatePending(poolId, scId_, amount, true, investor, depositAssetId, RequestType.Deposit);\n }\n\n /// @inheritdoc IShareClassManager\n function cancelDepositRequest(PoolId poolId, ShareClassId scId_, bytes32 investor, AssetId depositAssetId)\n external\n auth\n returns (uint128 cancelledAssetAmount)\n {\n require(exists(poolId, scId_), ShareClassNotFound());\n\n uint128 cancellingAmount = depositRequest[scId_][depositAssetId][investor].pending;\n\n return _updatePending(poolId, scId_, cancellingAmount, false, investor, depositAssetId, RequestType.Deposit);\n }\n\n /// @inheritdoc IShareClassManager\n function requestRedeem(PoolId poolId, ShareClassId scId_, uint128 amount, bytes32 investor, AssetId payoutAssetId)\n external\n auth\n {\n require(exists(poolId, scId_), ShareClassNotFound());\n\n // NOTE: CV ensures amount > 0\n _updatePending(poolId, scId_, amount, true, investor, payoutAssetId, RequestType.Redeem);\n }\n\n /// @inheritdoc IShareClassManager\n function cancelRedeemRequest(PoolId poolId, ShareClassId scId_, bytes32 investor, AssetId payoutAssetId)\n external\n auth\n returns (uint128 cancelledShareAmount)\n {\n require(exists(poolId, scId_), ShareClassNotFound());\n\n uint128 cancellingAmount = redeemRequest[scId_][payoutAssetId][investor].pending;\n\n return _updatePending(poolId, scId_, cancellingAmount, false, investor, payoutAssetId, RequestType.Redeem);\n }\n\n //----------------------------------------------------------------------------------------------\n // Manager actions\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IShareClassManager\n function approveDeposits(\n PoolId poolId,\n ShareClassId scId_,\n AssetId depositAssetId,\n uint32 nowDepositEpochId,\n uint128 approvedAssetAmount,\n D18 pricePoolPerAsset\n ) external auth returns (uint128 pendingAssetAmount, uint128 approvedPoolAmount) {\n require(exists(poolId, scId_), ShareClassNotFound());\n require(\n nowDepositEpochId == nowDepositEpoch(scId_, depositAssetId),\n EpochNotInSequence(nowDepositEpochId, nowDepositEpoch(scId_, depositAssetId))\n );\n\n // Limit in case approved > pending due to race condition of FM approval and async incoming requests\n pendingAssetAmount = pendingDeposit[scId_][depositAssetId];\n require(approvedAssetAmount <= pendingAssetAmount, InsufficientPending());\n require(approvedAssetAmount > 0, ZeroApprovalAmount());\n\n approvedPoolAmount = PricingLib.convertWithPrice(\n approvedAssetAmount, hubRegistry.decimals(depositAssetId), hubRegistry.decimals(poolId), pricePoolPerAsset\n ).toUint128();\n\n // Update epoch data\n EpochInvestAmounts storage epochAmounts = epochInvestAmounts[scId_][depositAssetId][nowDepositEpochId];\n epochAmounts.approvedAssetAmount = approvedAssetAmount;\n epochAmounts.approvedPoolAmount = approvedPoolAmount;\n epochAmounts.pendingAssetAmount = pendingAssetAmount;\n epochAmounts.pricePoolPerAsset = pricePoolPerAsset;\n\n // Reduce pending\n pendingDeposit[scId_][depositAssetId] -= approvedAssetAmount;\n pendingAssetAmount -= approvedAssetAmount;\n\n epochId[scId_][depositAssetId].deposit = nowDepositEpochId;\n emit ApproveDeposits(\n poolId,\n scId_,\n depositAssetId,\n nowDepositEpochId,\n approvedPoolAmount,\n approvedAssetAmount,\n pendingAssetAmount\n );\n }\n\n /// @inheritdoc IShareClassManager\n function approveRedeems(\n PoolId poolId,\n ShareClassId scId_,\n AssetId payoutAssetId,\n uint32 nowRedeemEpochId,\n uint128 approvedShareAmount,\n D18 pricePoolPerAsset\n ) external auth returns (uint128 pendingShareAmount) {\n require(exists(poolId, scId_), ShareClassNotFound());\n require(\n nowRedeemEpochId == nowRedeemEpoch(scId_, payoutAssetId),\n EpochNotInSequence(nowRedeemEpochId, nowRedeemEpoch(scId_, payoutAssetId))\n );\n\n // Limit in case approved > pending due to race condition of FM approval and async incoming requests\n pendingShareAmount = pendingRedeem[scId_][payoutAssetId];\n require(approvedShareAmount <= pendingShareAmount, InsufficientPending());\n require(approvedShareAmount > 0, ZeroApprovalAmount());\n\n // Update epoch data\n EpochRedeemAmounts storage epochAmounts = epochRedeemAmounts[scId_][payoutAssetId][nowRedeemEpochId];\n epochAmounts.approvedShareAmount = approvedShareAmount;\n epochAmounts.pendingShareAmount = pendingShareAmount;\n epochAmounts.pricePoolPerAsset = pricePoolPerAsset;\n\n // Reduce pending\n pendingRedeem[scId_][payoutAssetId] -= approvedShareAmount;\n pendingShareAmount -= approvedShareAmount;\n epochId[scId_][payoutAssetId].redeem = nowRedeemEpochId;\n emit ApproveRedeems(poolId, scId_, payoutAssetId, nowRedeemEpochId, approvedShareAmount, pendingShareAmount);\n }\n\n /// @inheritdoc IShareClassManager\n function issueShares(\n PoolId poolId,\n ShareClassId scId_,\n AssetId depositAssetId,\n uint32 nowIssueEpochId,\n D18 navPoolPerShare\n ) external auth returns (uint128 issuedShareAmount, uint128 depositAssetAmount, uint128 depositPoolAmount) {\n require(exists(poolId, scId_), ShareClassNotFound());\n require(nowIssueEpochId <= epochId[scId_][depositAssetId].deposit, EpochNotFound());\n require(\n nowIssueEpochId == nowIssueEpoch(scId_, depositAssetId),\n EpochNotInSequence(nowIssueEpochId, nowIssueEpoch(scId_, depositAssetId))\n );\n\n EpochInvestAmounts storage epochAmounts = epochInvestAmounts[scId_][depositAssetId][nowIssueEpochId];\n epochAmounts.navPoolPerShare = navPoolPerShare;\n\n issuedShareAmount = PricingLib.assetToShareAmount(\n epochAmounts.approvedAssetAmount,\n hubRegistry.decimals(depositAssetId),\n hubRegistry.decimals(poolId),\n epochAmounts.pricePoolPerAsset,\n navPoolPerShare,\n MathLib.Rounding.Down\n ).toUint128();\n\n metrics[scId_].totalIssuance += issuedShareAmount;\n epochAmounts.issuedAt = block.timestamp.toUint64();\n epochId[scId_][depositAssetId].issue = nowIssueEpochId;\n\n depositAssetAmount = epochAmounts.approvedAssetAmount;\n depositPoolAmount = epochAmounts.approvedPoolAmount;\n\n emit IssueShares(\n poolId,\n scId_,\n depositAssetId,\n nowIssueEpochId,\n navPoolPerShare,\n PricingLib.priceAssetPerShare(epochAmounts.navPoolPerShare, epochAmounts.pricePoolPerAsset),\n issuedShareAmount\n );\n }\n\n /// @inheritdoc IShareClassManager\n function revokeShares(\n PoolId poolId,\n ShareClassId scId_,\n AssetId payoutAssetId,\n uint32 nowRevokeEpochId,\n D18 navPoolPerShare\n ) external auth returns (uint128 revokedShareAmount, uint128 payoutAssetAmount, uint128 payoutPoolAmount) {\n require(exists(poolId, scId_), ShareClassNotFound());\n require(nowRevokeEpochId <= epochId[scId_][payoutAssetId].redeem, EpochNotFound());\n require(\n nowRevokeEpochId == nowRevokeEpoch(scId_, payoutAssetId),\n EpochNotInSequence(nowRevokeEpochId, nowRevokeEpoch(scId_, payoutAssetId))\n );\n\n EpochRedeemAmounts storage epochAmounts = epochRedeemAmounts[scId_][payoutAssetId][nowRevokeEpochId];\n epochAmounts.navPoolPerShare = navPoolPerShare;\n\n require(epochAmounts.approvedShareAmount <= metrics[scId_].totalIssuance, RevokeMoreThanIssued());\n\n // NOTE: shares and pool currency have the same decimals - no conversion needed!\n payoutPoolAmount = navPoolPerShare.mulUint128(epochAmounts.approvedShareAmount, MathLib.Rounding.Down);\n\n payoutAssetAmount = PricingLib.poolToAssetAmount(\n payoutPoolAmount,\n hubRegistry.decimals(poolId),\n hubRegistry.decimals(payoutAssetId),\n epochAmounts.pricePoolPerAsset,\n MathLib.Rounding.Down\n ).toUint128();\n revokedShareAmount = epochAmounts.approvedShareAmount;\n\n metrics[scId_].totalIssuance -= epochAmounts.approvedShareAmount;\n epochAmounts.payoutAssetAmount = payoutAssetAmount;\n epochAmounts.revokedAt = block.timestamp.toUint64();\n epochId[scId_][payoutAssetId].revoke = nowRevokeEpochId;\n\n emit RevokeShares(\n poolId,\n scId_,\n payoutAssetId,\n nowRevokeEpochId,\n navPoolPerShare,\n PricingLib.priceAssetPerShare(epochAmounts.navPoolPerShare, epochAmounts.pricePoolPerAsset),\n epochAmounts.approvedShareAmount,\n payoutAssetAmount,\n payoutPoolAmount\n );\n }\n\n /// @inheritdoc IShareClassManager\n function updatePricePerShare(PoolId poolId, ShareClassId scId_, D18 navPoolPerShare) external auth {\n require(exists(poolId, scId_), ShareClassNotFound());\n\n ShareClassMetrics storage m = metrics[scId_];\n m.navPerShare = navPoolPerShare;\n emit UpdateShareClass(poolId, scId_, navPoolPerShare);\n }\n\n /// @inheritdoc IShareClassManager\n function updateMetadata(PoolId poolId, ShareClassId scId_, string calldata name, string calldata symbol)\n external\n auth\n {\n require(exists(poolId, scId_), ShareClassNotFound());\n\n _updateMetadata(scId_, name, symbol, bytes32(0));\n\n emit UpdateMetadata(poolId, scId_, name, symbol);\n }\n\n /// @inheritdoc IShareClassManager\n function increaseShareClassIssuance(PoolId poolId, ShareClassId scId_, uint128 amount) external auth {\n require(exists(poolId, scId_), ShareClassNotFound());\n\n uint128 newIssuance = metrics[scId_].totalIssuance + amount;\n metrics[scId_].totalIssuance = newIssuance;\n\n emit RemoteIssueShares(poolId, scId_, amount);\n }\n\n /// @inheritdoc IShareClassManager\n function decreaseShareClassIssuance(PoolId poolId, ShareClassId scId_, uint128 amount) external auth {\n require(exists(poolId, scId_), ShareClassNotFound());\n require(metrics[scId_].totalIssuance >= amount, DecreaseMoreThanIssued());\n\n uint128 newIssuance = metrics[scId_].totalIssuance - amount;\n metrics[scId_].totalIssuance = newIssuance;\n\n emit RemoteRevokeShares(poolId, scId_, amount);\n }\n\n //----------------------------------------------------------------------------------------------\n // Claiming methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IShareClassManager\n function claimDeposit(PoolId poolId, ShareClassId scId_, bytes32 investor, AssetId depositAssetId)\n public\n auth\n returns (\n uint128 payoutShareAmount,\n uint128 paymentAssetAmount,\n uint128 cancelledAssetAmount,\n bool canClaimAgain\n )\n {\n require(exists(poolId, scId_), ShareClassNotFound());\n\n UserOrder storage userOrder = depositRequest[scId_][depositAssetId][investor];\n require(userOrder.pending > 0, NoOrderFound());\n require(userOrder.lastUpdate <= epochId[scId_][depositAssetId].issue, IssuanceRequired());\n canClaimAgain = userOrder.lastUpdate < epochId[scId_][depositAssetId].issue;\n EpochInvestAmounts storage epochAmounts = epochInvestAmounts[scId_][depositAssetId][userOrder.lastUpdate];\n\n paymentAssetAmount = epochAmounts.approvedAssetAmount == 0\n ? 0\n : userOrder.pending.mulDiv(epochAmounts.approvedAssetAmount, epochAmounts.pendingAssetAmount).toUint128();\n\n // NOTE: Due to precision loss, the sum of claimable user amounts is leq than the amount of minted share class\n // tokens corresponding to the approved share amount (instead of equality). I.e., it is possible for an epoch to\n // have an excess of a share class tokens which cannot be claimed by anyone.\n // This excess is at most n-1 share tokens for an epoch with n claimable users.\n if (paymentAssetAmount > 0) {\n uint256 paymentPoolAmount = PricingLib.convertWithPrice(\n paymentAssetAmount,\n hubRegistry.decimals(depositAssetId),\n hubRegistry.decimals(poolId),\n epochAmounts.pricePoolPerAsset\n );\n payoutShareAmount =\n epochAmounts.navPoolPerShare.reciprocalMulUint256(paymentPoolAmount, MathLib.Rounding.Down).toUint128();\n\n userOrder.pending -= paymentAssetAmount;\n }\n\n emit ClaimDeposit(\n poolId,\n scId_,\n userOrder.lastUpdate,\n investor,\n depositAssetId,\n paymentAssetAmount,\n userOrder.pending,\n payoutShareAmount,\n epochAmounts.issuedAt\n );\n\n // If there is nothing to claim anymore we can short circuit to the latest epoch\n if (userOrder.pending == 0) {\n // The current epoch is always one step ahead of the stored one\n userOrder.lastUpdate = nowDepositEpoch(scId_, depositAssetId);\n canClaimAgain = false;\n } else {\n userOrder.lastUpdate += 1;\n }\n\n // If user claimed up to latest approval epoch, move queued to pending\n if (userOrder.lastUpdate == nowDepositEpoch(scId_, depositAssetId)) {\n cancelledAssetAmount =\n _postClaimUpdateQueued(poolId, scId_, investor, depositAssetId, userOrder, RequestType.Deposit);\n }\n }\n\n /// @inheritdoc IShareClassManager\n function claimRedeem(PoolId poolId, ShareClassId scId_, bytes32 investor, AssetId payoutAssetId)\n public\n auth\n returns (\n uint128 payoutAssetAmount,\n uint128 paymentShareAmount,\n uint128 cancelledShareAmount,\n bool canClaimAgain\n )\n {\n require(exists(poolId, scId_), ShareClassNotFound());\n\n UserOrder storage userOrder = redeemRequest[scId_][payoutAssetId][investor];\n require(userOrder.pending > 0, NoOrderFound());\n require(userOrder.lastUpdate <= epochId[scId_][payoutAssetId].revoke, RevocationRequired());\n canClaimAgain = userOrder.lastUpdate < epochId[scId_][payoutAssetId].revoke;\n\n EpochRedeemAmounts storage epochAmounts = epochRedeemAmounts[scId_][payoutAssetId][userOrder.lastUpdate];\n\n paymentShareAmount = epochAmounts.approvedShareAmount == 0\n ? 0\n : userOrder.pending.mulDiv(epochAmounts.approvedShareAmount, epochAmounts.pendingShareAmount).toUint128();\n\n // NOTE: Due to precision loss, the sum of claimable user amounts is leq than the amount of minted share class\n // tokens corresponding to the approved share amount (instead of equality). I.e., it is possible for an epoch to\n // have an excess of a share class tokens which cannot be claimed by anyone.\n // This excess is at most n-1 share tokens for an epoch with n claimable users.\n if (paymentShareAmount > 0) {\n payoutAssetAmount = PricingLib.shareToAssetAmount(\n paymentShareAmount,\n hubRegistry.decimals(poolId),\n hubRegistry.decimals(payoutAssetId),\n epochAmounts.pricePoolPerAsset,\n epochAmounts.navPoolPerShare,\n MathLib.Rounding.Down\n ).toUint128();\n\n userOrder.pending -= paymentShareAmount;\n }\n\n emit ClaimRedeem(\n poolId,\n scId_,\n userOrder.lastUpdate,\n investor,\n payoutAssetId,\n paymentShareAmount,\n userOrder.pending,\n payoutAssetAmount,\n epochAmounts.revokedAt\n );\n\n // If there is nothing to claim anymore we can short circuit the in between epochs\n if (userOrder.pending == 0) {\n // The current epoch is always one step ahead of the stored one\n userOrder.lastUpdate = nowRedeemEpoch(scId_, payoutAssetId);\n canClaimAgain = false;\n } else {\n userOrder.lastUpdate += 1;\n }\n\n if (userOrder.lastUpdate == nowRedeemEpoch(scId_, payoutAssetId)) {\n cancelledShareAmount =\n _postClaimUpdateQueued(poolId, scId_, investor, payoutAssetId, userOrder, RequestType.Redeem);\n }\n }\n\n //----------------------------------------------------------------------------------------------\n // View methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IShareClassManager\n function previewNextShareClassId(PoolId poolId) public view returns (ShareClassId scId) {\n return newShareClassId(poolId, shareClassCount[poolId] + 1);\n }\n\n /// @inheritdoc IShareClassManager\n function previewShareClassId(PoolId poolId, uint32 index) public pure returns (ShareClassId scId) {\n return newShareClassId(poolId, index);\n }\n\n /// @inheritdoc IShareClassManager\n function exists(PoolId poolId, ShareClassId scId_) public view returns (bool) {\n return shareClassIds[poolId][scId_];\n }\n\n /// @inheritdoc IShareClassManager\n function nowDepositEpoch(ShareClassId scId_, AssetId depositAssetId) public view returns (uint32) {\n return epochId[scId_][depositAssetId].deposit + 1;\n }\n\n /// @inheritdoc IShareClassManager\n function nowIssueEpoch(ShareClassId scId_, AssetId depositAssetId) public view returns (uint32) {\n return epochId[scId_][depositAssetId].issue + 1;\n }\n\n /// @inheritdoc IShareClassManager\n function nowRedeemEpoch(ShareClassId scId_, AssetId depositAssetId) public view returns (uint32) {\n return epochId[scId_][depositAssetId].redeem + 1;\n }\n\n /// @inheritdoc IShareClassManager\n function nowRevokeEpoch(ShareClassId scId_, AssetId depositAssetId) public view returns (uint32) {\n return epochId[scId_][depositAssetId].revoke + 1;\n }\n\n /// @inheritdoc IShareClassManager\n function maxDepositClaims(ShareClassId scId_, bytes32 investor, AssetId depositAssetId)\n public\n view\n returns (uint32)\n {\n return _maxClaims(depositRequest[scId_][depositAssetId][investor], epochId[scId_][depositAssetId].deposit);\n }\n\n /// @inheritdoc IShareClassManager\n function maxRedeemClaims(ShareClassId scId_, bytes32 investor, AssetId payoutAssetId)\n public\n view\n returns (uint32)\n {\n return _maxClaims(redeemRequest[scId_][payoutAssetId][investor], epochId[scId_][payoutAssetId].redeem);\n }\n\n function _maxClaims(UserOrder memory userOrder, uint32 lastEpoch) private pure returns (uint32) {\n // User order either not set or not processed\n if (userOrder.pending == 0 || userOrder.lastUpdate > lastEpoch) {\n return 0;\n }\n\n return lastEpoch - userOrder.lastUpdate + 1;\n }\n\n //----------------------------------------------------------------------------------------------\n // Internal methods\n //----------------------------------------------------------------------------------------------\n\n function _updateMetadata(ShareClassId scId_, string calldata name, string calldata symbol, bytes32 salt) private {\n uint256 nameLen = bytes(name).length;\n require(nameLen > 0 && nameLen <= 128, InvalidMetadataName());\n\n uint256 symbolLen = bytes(symbol).length;\n require(symbolLen > 0 && symbolLen <= 32, InvalidMetadataSymbol());\n\n ShareClassMetadata storage meta = metadata[scId_];\n\n // Ensure that the salt is not being updated or is being set for the first time\n require(\n (salt == bytes32(0) && meta.salt != bytes32(0)) || (salt != bytes32(0) && meta.salt == bytes32(0)),\n InvalidSalt()\n );\n\n if (salt != bytes32(0) && meta.salt == bytes32(0)) {\n require(!salts[salt], AlreadyUsedSalt());\n salts[salt] = true;\n meta.salt = salt;\n }\n\n meta.name = name;\n meta.symbol = symbol;\n }\n\n function _postClaimUpdateQueued(\n PoolId poolId,\n ShareClassId scId_,\n bytes32 investor,\n AssetId assetId,\n UserOrder storage userOrder,\n RequestType requestType\n ) private returns (uint128 cancelledAmount) {\n QueuedOrder storage queued = requestType == RequestType.Deposit\n ? queuedDepositRequest[scId_][assetId][investor]\n : queuedRedeemRequest[scId_][assetId][investor];\n\n // Increment pending by queued or cancel everything\n uint128 updatePendingAmount = queued.isCancelling ? userOrder.pending : queued.amount;\n if (queued.isCancelling) {\n cancelledAmount = userOrder.pending + queued.amount;\n userOrder.pending = 0;\n } else {\n userOrder.pending += queued.amount;\n }\n\n if (requestType == RequestType.Deposit) {\n _updatePendingDeposit(\n poolId,\n scId_,\n updatePendingAmount,\n !queued.isCancelling,\n investor,\n assetId,\n userOrder,\n QueuedOrder(false, 0)\n );\n } else {\n _updatePendingRedeem(\n poolId,\n scId_,\n updatePendingAmount,\n !queued.isCancelling,\n investor,\n assetId,\n userOrder,\n QueuedOrder(false, 0)\n );\n }\n\n // Clear queued\n queued.isCancelling = false;\n queued.amount = 0;\n }\n\n /// @notice Updates the amount of a deposit or redeem request.\n ///\n /// @param poolId Identifier of the pool\n /// @param scId_ Identifier of the share class\n /// @param amount Amount which is updated\n /// @param isIncrement Whether the amount is positive (additional request) or negative (cancellation)\n /// @param investor Address of the entity which is depositing\n /// @param assetId Identifier of the asset which the investor either used as deposit or wants to redeem to\n /// @param requestType Flag indicating whether the request is a deposit or redeem request\n /// @return cancelledAmount Pending amount which was cancelled\n function _updatePending(\n PoolId poolId,\n ShareClassId scId_,\n uint128 amount,\n bool isIncrement,\n bytes32 investor,\n AssetId assetId,\n RequestType requestType\n ) private returns (uint128 cancelledAmount) {\n UserOrder storage userOrder = requestType == RequestType.Deposit\n ? depositRequest[scId_][assetId][investor]\n : redeemRequest[scId_][assetId][investor];\n QueuedOrder storage queued = requestType == RequestType.Deposit\n ? queuedDepositRequest[scId_][assetId][investor]\n : queuedRedeemRequest[scId_][assetId][investor];\n\n // We must only update either queued or pending\n if (_updateQueued(poolId, scId_, amount, isIncrement, investor, assetId, userOrder, queued, requestType)) {\n return 0;\n }\n\n cancelledAmount = isIncrement ? 0 : amount;\n // NOTE: If we decrease the pending, we decrease usually by the full amount\n // We keep subtraction of amount over setting to zero on purpose to not limit future higher level logic\n userOrder.pending = isIncrement ? userOrder.pending + amount : userOrder.pending - amount;\n\n userOrder.lastUpdate =\n requestType == RequestType.Deposit ? nowDepositEpoch(scId_, assetId) : nowRedeemEpoch(scId_, assetId);\n\n if (requestType == RequestType.Deposit) {\n _updatePendingDeposit(poolId, scId_, amount, isIncrement, investor, assetId, userOrder, queued);\n } else {\n _updatePendingRedeem(poolId, scId_, amount, isIncrement, investor, assetId, userOrder, queued);\n }\n }\n\n /// @notice Checks whether the pending amount can be updated. If not, it updates the queued amount.\n ///\n /// @param poolId Identifier of the pool\n /// @param scId_ Identifier of the share class\n /// @param amount Amount which is updated\n /// @param isIncrement Whether the amount is positive (additional request) or negative (cancellation)\n /// @param investor Address of the entity which is depositing\n /// @param assetId Identifier of the asset which the investor either used as deposit or wants to redeem to\n /// @param userOrder User order storage for the deposit or redeem request\n /// @param requestType Flag indicating whether the request is a deposit or redeem request\n /// @return skipPendingUpdate Flag indicating whether the pending amount can be updated which is true if the user\n /// does not need to claim\n function _updateQueued(\n PoolId poolId,\n ShareClassId scId_,\n uint128 amount,\n bool isIncrement,\n bytes32 investor,\n AssetId assetId,\n UserOrder storage userOrder,\n QueuedOrder storage queued,\n RequestType requestType\n ) private returns (bool skipPendingUpdate) {\n uint32 lastEpoch =\n requestType == RequestType.Deposit ? epochId[scId_][assetId].deposit : epochId[scId_][assetId].redeem;\n uint32 currentEpoch = lastEpoch + 1;\n\n // Short circuit if user can mutate pending, i.e. last update happened after latest approval or is first update\n if (userOrder.lastUpdate == currentEpoch || userOrder.pending == 0 || lastEpoch == 0) {\n return false;\n }\n\n // Block increasing queued amount if cancelling is already queued\n // NOTE: Can only happen due to race condition as CV blocks requests if cancellation is in progress\n require(!(queued.isCancelling && amount > 0), CancellationQueued());\n\n if (!isIncrement) {\n queued.isCancelling = true;\n } else {\n queued.amount += amount;\n }\n\n if (requestType == RequestType.Deposit) {\n uint128 pendingTotal = pendingDeposit[scId_][assetId];\n emit UpdateDepositRequest(\n poolId,\n scId_,\n assetId,\n currentEpoch,\n investor,\n userOrder.pending,\n pendingTotal,\n queued.amount,\n queued.isCancelling\n );\n } else {\n uint128 pendingTotal = pendingRedeem[scId_][assetId];\n\n emit UpdateRedeemRequest(\n poolId,\n scId_,\n assetId,\n currentEpoch,\n investor,\n userOrder.pending,\n pendingTotal,\n queued.amount,\n queued.isCancelling\n );\n }\n\n return true;\n }\n\n function _updatePendingDeposit(\n PoolId poolId,\n ShareClassId scId_,\n uint128 amount,\n bool isIncrement,\n bytes32 investor,\n AssetId assetId,\n UserOrder storage userOrder,\n QueuedOrder memory queued\n ) private {\n uint128 pendingTotal = pendingDeposit[scId_][assetId];\n pendingTotal = isIncrement ? pendingTotal + amount : pendingTotal - amount;\n pendingDeposit[scId_][assetId] = pendingTotal;\n\n emit UpdateDepositRequest(\n poolId,\n scId_,\n assetId,\n nowDepositEpoch(scId_, assetId),\n investor,\n userOrder.pending,\n pendingTotal,\n queued.amount,\n queued.isCancelling\n );\n }\n\n function _updatePendingRedeem(\n PoolId poolId,\n ShareClassId scId_,\n uint128 amount,\n bool isIncrement,\n bytes32 investor,\n AssetId assetId,\n UserOrder storage userOrder,\n QueuedOrder memory queued\n ) private {\n uint128 pendingTotal = pendingRedeem[scId_][assetId];\n pendingTotal = isIncrement ? pendingTotal + amount : pendingTotal - amount;\n pendingRedeem[scId_][assetId] = pendingTotal;\n\n emit UpdateRedeemRequest(\n poolId,\n scId_,\n assetId,\n nowRedeemEpoch(scId_, assetId),\n investor,\n userOrder.pending,\n pendingTotal,\n queued.amount,\n queued.isCancelling\n );\n }\n}\n" + }, + "src/hub/interfaces/IAccounting.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {AccountId} from \"src/common/types/AccountId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\n\nstruct JournalEntry {\n uint128 value;\n AccountId accountId;\n}\n\ninterface IAccounting {\n /// @notice Emitted when a an entry is done\n event Credit(PoolId indexed poolId, AccountId indexed account, uint128 value);\n event Debit(PoolId indexed poolId, AccountId indexed account, uint128 value);\n\n /// @notice Emitted at the beginning and end of a journal entry\n event StartJournalId(PoolId indexed poolId, uint256 journalId);\n event EndJournalId(PoolId indexed poolId, uint256 journalId);\n\n /// @notice Emitted when a new account is created\n event CreateAccount(PoolId indexed poolId, AccountId indexed account, bool isDebitNormal);\n\n /// @notice Emitted when metadata is set for an account\n event SetAccountMetadata(PoolId indexed poolId, AccountId indexed account, bytes metadata);\n\n /// @notice Dispatched when the pool is already unlocked.\n error AccountingAlreadyUnlocked();\n\n /// @notice Dispatched when the pool is not unlocked to interact with.\n error AccountingLocked();\n\n /// @notice Dispatched when the debit and credit side do not match at the end of a transaction.\n error Unbalanced();\n\n /// @notice Dispatched when trying to create an account that already exists.\n error AccountExists();\n\n /// @notice Dispatched when trying debit or credit an account that doesn't exists.\n error AccountDoesNotExist();\n\n /// @notice Represents an account\n struct Account {\n uint128 totalDebit;\n uint128 totalCredit;\n bool isDebitNormal;\n uint64 lastUpdated;\n bytes metadata;\n }\n\n /// @notice Debits an account. Increase the value of debit-normal accounts, decrease for credit-normal ones.\n /// @param account The account to debit\n /// @param value Amount being debited\n function addDebit(AccountId account, uint128 value) external;\n\n /// @notice Credits an account. Decrease the value of debit-normal accounts, increase for credit-normal ones.\n /// @param account The account to credit\n /// @param value Amount being credited\n function addCredit(AccountId account, uint128 value) external;\n\n /// @notice Apply addDebit and addCredit to each journal entry\n function addJournal(JournalEntry[] memory debits, JournalEntry[] memory credits) external;\n\n /// @notice Unlocks a pool for journal entries\n /// @param poolId The pool to unlock\n function unlock(PoolId poolId) external;\n\n /// @notice Closes the transaction and checks if the entries are balanced.\n function lock() external;\n\n /// @notice Creates an account.\n /// @param poolId The pool the account belongs to\n /// @param account The account to create\n /// @param isDebitNormal Whether the account is debit-normal or credit-normal\n function createAccount(PoolId poolId, AccountId account, bool isDebitNormal) external;\n\n /// @notice Sets metadata associated to an existent account.\n /// @param poolId The pool the account belongs to\n /// @param account The account to set metadata for\n /// @param metadata The metadata to set\n function setAccountMetadata(PoolId poolId, AccountId account, bytes calldata metadata) external;\n\n /// @notice Returns the value of an account\n /// @param poolId The pool the account belongs to\n /// @param account The account to get the value of\n /// @return isPositive Indicates whether value is a positive or negative value\n /// @return value The value of the account\n function accountValue(PoolId poolId, AccountId account) external view returns (bool isPositive, uint128 value);\n\n /// @notice Returns whether an account exists\n /// @param poolId The pool the account belongs to\n /// @param account The account to check\n /// @return True if the account exists, false otherwise\n function exists(PoolId poolId, AccountId account) external view returns (bool);\n}\n" + }, + "src/hub/interfaces/IHoldings.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IERC7726} from \"src/misc/interfaces/IERC7726.sol\";\nimport {D18} from \"src/misc/types/D18.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {AccountId} from \"src/common/types/AccountId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nstruct Holding {\n uint128 assetAmount;\n uint128 assetAmountValue;\n IERC7726 valuation; // Used for existence\n bool isLiability;\n}\n\nstruct HoldingAccount {\n AccountId accountId;\n uint8 kind;\n}\n\ninterface IHoldings {\n /// @notice Emitted when a holding is created\n event Create(\n PoolId indexed,\n ShareClassId indexed scId,\n AssetId indexed assetId,\n IERC7726 valuation,\n bool isLiability,\n HoldingAccount[] accounts\n );\n\n /// @notice Emitted when a holding is increased\n event Increase(\n PoolId indexed,\n ShareClassId indexed scId,\n AssetId indexed assetId,\n D18 pricePoolPerAsset,\n uint128 amount,\n uint128 increasedValue\n );\n\n /// @notice Emitted when a holding is decreased\n event Decrease(\n PoolId indexed,\n ShareClassId indexed scId,\n AssetId indexed assetId,\n D18 pricePoolPerAsset,\n uint128 amount,\n uint128 decreasedValue\n );\n\n /// @notice Emitted when the holding is updated\n event Update(\n PoolId indexed, ShareClassId indexed scId, AssetId indexed assetId, bool isPositive, uint128 diffValue\n );\n\n /// @notice Emitted when a holding valuation is updated\n event UpdateValuation(PoolId indexed, ShareClassId indexed scId, AssetId indexed assetId, IERC7726 valuation);\n\n /// @notice Emitted when an account is for a holding is set\n event SetAccountId(\n PoolId indexed, ShareClassId indexed scId, AssetId indexed assetId, uint8 kind, AccountId accountId\n );\n\n /// @notice Item was not found for a required action\n error HoldingNotFound();\n\n /// @notice Valuation is not valid.\n error WrongValuation();\n\n /// @notice ShareClassId is not valid.\n error WrongShareClassId();\n\n /// @notice AssetId is not valid.\n error WrongAssetId();\n\n /// @notice Creates a new holding in a pool using a valuation\n function create(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n IERC7726 valuation,\n bool isLiability,\n HoldingAccount[] memory accounts\n ) external;\n\n /// @notice Increments the amount of a holding and updates the value for that increment.\n /// @return value The value the holding has increment.\n function increase(PoolId poolId, ShareClassId scId, AssetId assetId, D18 pricePoolPerAsset, uint128 amount)\n external\n returns (uint128 value);\n\n /// @notice Decrements the amount of a holding and updates the value for that decrement.\n /// @return value The value the holding has decrement.\n function decrease(PoolId poolId, ShareClassId scId, AssetId assetId, D18 pricePoolPerAsset, uint128 amount)\n external\n returns (uint128 value);\n\n /// @notice Reset the value of a holding using the current valuation.\n /// @return isPositive Indicates whether the diffValue is positive or negative\n /// @return diffValue The difference in value after the new valuation.\n function update(PoolId poolId, ShareClassId scId, AssetId assetId)\n external\n returns (bool isPositive, uint128 diffValue);\n\n /// @notice Updates the valuation method used for this holding.\n function updateValuation(PoolId poolId, ShareClassId scId, AssetId assetId, IERC7726 valuation) external;\n\n /// @notice Sets an account id for an specific kind\n function setAccountId(PoolId poolId, ShareClassId scId, AssetId assetId, uint8 kind, AccountId accountId)\n external;\n\n /// @notice Returns the value of this holding.\n function value(PoolId poolId, ShareClassId scId, AssetId assetId) external view returns (uint128 value);\n\n /// @notice Returns the amount of this holding.\n function amount(PoolId poolId, ShareClassId scId, AssetId assetId) external view returns (uint128 amount);\n\n /// @notice Returns the valuation method used for this holding.\n function valuation(PoolId poolId, ShareClassId scId, AssetId assetId) external view returns (IERC7726);\n\n /// @notice Returns if the holding is a liability\n function isLiability(PoolId poolId, ShareClassId scId, AssetId assetId) external view returns (bool);\n\n /// @notice Returns an account id for an specific kind\n function accountId(PoolId poolId, ShareClassId scId, AssetId assetId, uint8 kind)\n external\n view\n returns (AccountId);\n\n /// @notice Tells if the holding exists for an asset in a share class\n function exists(PoolId poolId, ShareClassId scId, AssetId assetId) external view returns (bool);\n}\n" + }, + "src/hub/interfaces/IHub.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {D18} from \"src/misc/types/D18.sol\";\nimport {IERC7726} from \"src/misc/interfaces/IERC7726.sol\";\n\nimport {VaultUpdateKind} from \"src/common/libraries/MessageLib.sol\";\nimport {IGateway} from \"src/common/interfaces/IGateway.sol\";\nimport {IPoolMessageSender} from \"src/common/interfaces/IGatewaySenders.sol\";\n\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {AccountId} from \"src/common/types/AccountId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {IShareClassManager} from \"src/hub/interfaces/IShareClassManager.sol\";\nimport {IAccounting, JournalEntry} from \"src/hub/interfaces/IAccounting.sol\";\nimport {IHubRegistry} from \"src/hub/interfaces/IHubRegistry.sol\";\nimport {IHoldings} from \"src/hub/interfaces/IHoldings.sol\";\n\n/// @notice Account types used by Hub\nenum AccountType {\n /// @notice Debit normal account for tracking assets\n Asset,\n /// @notice Credit normal account for tracking equities\n Equity,\n /// @notice Credit normal account for tracking losses\n Loss,\n /// @notice Credit normal account for tracking profits\n Gain,\n /// @notice Debit normal account for tracking expenses\n Expense,\n /// @notice Credit normal account for tracking liabilities\n Liability\n}\n\n/// @notice Interface with all methods available in the system used by actors\ninterface IHub {\n event NotifyPool(uint16 indexed centrifugeId, PoolId indexed poolId);\n event NotifyShareClass(uint16 indexed centrifugeId, PoolId indexed poolId, ShareClassId scId);\n event NotifyShareMetadata(\n uint16 indexed centrifugeId, PoolId indexed poolId, ShareClassId scId, string name, string symbol\n );\n event UpdateShareHook(uint16 indexed centrifugeId, PoolId indexed poolId, ShareClassId scId, bytes32 hook);\n event NotifySharePrice(uint16 indexed centrifugeId, PoolId indexed poolId, ShareClassId scId, D18 poolPerShare);\n event NotifyAssetPrice(\n uint16 indexed centrifugeId, PoolId indexed poolId, ShareClassId scId, AssetId assetId, D18 pricePoolPerAsset\n );\n event UpdateRestriction(uint16 indexed centrifugeId, PoolId indexed poolId, ShareClassId scId, bytes payload);\n event UpdateContract(\n uint16 indexed centrifugeId, PoolId indexed poolId, ShareClassId scId, bytes32 target, bytes payload\n );\n\n /// @notice Emitted when a call to `file()` was performed.\n event File(bytes32 what, address addr);\n\n /// @notice Dispatched when the `what` parameter of `file()` is not supported by the implementation.\n error FileUnrecognizedParam();\n\n /// @notice Dispatched when the pool is already unlocked.\n /// It means when calling to `execute()` inside `execute()`.\n error PoolAlreadyUnlocked();\n\n /// @notice Dispatched when the pool can not be unlocked by the caller\n error NotManager();\n\n /// @notice Dispatched when an invalid centrifuge ID is set in the pool ID.\n error InvalidPoolId();\n\n function gateway() external view returns (IGateway);\n function holdings() external view returns (IHoldings);\n function accounting() external view returns (IAccounting);\n function hubRegistry() external view returns (IHubRegistry);\n function sender() external view returns (IPoolMessageSender);\n function shareClassManager() external view returns (IShareClassManager);\n\n /// @notice Updates a contract parameter.\n /// @param what Name of the parameter to update.\n /// Accepts a `bytes32` representation of 'hubRegistry', 'assetRegistry', 'accounting', 'holdings', 'gateway' and '\n /// sender' as string value.\n function file(bytes32 what, address data) external;\n\n /// @notice Notify a deposit for an investor address located in the chain where the asset belongs\n function notifyDeposit(PoolId poolId, ShareClassId scId, AssetId depositAssetId, bytes32 investor, uint32 maxClaims)\n external\n payable;\n\n /// @notice Notify a redemption for an investor address located in the chain where the asset belongs\n function notifyRedeem(PoolId poolId, ShareClassId scId, AssetId payoutAssetId, bytes32 investor, uint32 maxClaims)\n external\n payable;\n\n /// @notice Notify to a CV instance that a new pool is available\n /// @param centrifugeId Chain where CV instance lives\n function notifyPool(PoolId poolId, uint16 centrifugeId) external payable;\n\n /// @notice Notify to a CV instance that a new share class is available\n /// @param centrifugeId Chain where CV instance lives\n /// @param hook The hook address of the share class\n function notifyShareClass(PoolId poolId, ShareClassId scId, uint16 centrifugeId, bytes32 hook) external payable;\n\n /// @notice Notify to a CV instance that share metadata has updated\n function notifyShareMetadata(PoolId poolId, ShareClassId scId, uint16 centrifugeId) external payable;\n\n /// @notice Update on a CV instance the hook of a share token\n function updateShareHook(PoolId poolId, ShareClassId scId, uint16 centrifugeId, bytes32 hook) external payable;\n\n /// @notice Notify to a CV instance the latest available price in POOL_UNIT / SHARE_UNIT\n /// @dev The receiving centrifugeId is derived from the provided assetId\n /// @param centrifugeId Chain to where the share price is notified\n /// @param scId Identifier of the share class\n function notifySharePrice(PoolId poolId, ShareClassId scId, uint16 centrifugeId) external payable;\n\n /// @notice Notify to a CV instance the latest available price in POOL_UNIT / ASSET_UNIT\n /// @dev The receiving centrifugeId is derived from the provided assetId\n /// @param scId Identifier of the share class\n /// @param assetId Identifier of the asset\n function notifyAssetPrice(PoolId poolId, ShareClassId scId, AssetId assetId) external payable;\n\n /// @notice Attach custom data to a pool\n function setPoolMetadata(PoolId poolId, bytes calldata metadata) external payable;\n\n /// @notice Update name & symbol of share class\n function updateShareClassMetadata(PoolId poolId, ShareClassId scId, string calldata name, string calldata symbol)\n external\n payable;\n\n /// @notice Allow/disallow an account to interact as pool manager\n function updateManager(PoolId poolId, address who, bool canManage) external payable;\n\n /// @notice Add a new share class to the pool\n function addShareClass(PoolId poolId, string calldata name, string calldata symbol, bytes32 salt)\n external\n payable\n returns (ShareClassId scId);\n\n /// @notice Approves an asset amount of all deposit requests for the given triplet of pool id, share class id and\n /// deposit asset id.\n /// @param scId Identifier of the share class\n /// @param depositAssetId Identifier of the asset locked for the deposit request\n /// @param nowDepositEpochId The epoch for which deposits will be approved.\n /// @param approvedAssetAmount Ampunt of assets that will be approved\n function approveDeposits(\n PoolId poolId,\n ShareClassId scId,\n AssetId depositAssetId,\n uint32 nowDepositEpochId,\n uint128 approvedAssetAmount\n ) external payable returns (uint128 pendingAssetAmount, uint128 approvedPoolAmount);\n\n /// @notice Approves a percentage of all redemption requests for the given triplet of pool id, share class id and\n /// deposit asset id.\n /// @param scId Identifier of the share class\n /// @param payoutAssetId Identifier of the asset for which all requests want to exchange their share class tokens\n /// @param nowRedeemEpochId The epoch for which redemptions will be approved.\n /// @param approvedShareAmount Amount of shares that will be approved\n function approveRedeems(\n PoolId poolId,\n ShareClassId scId,\n AssetId payoutAssetId,\n uint32 nowRedeemEpochId,\n uint128 approvedShareAmount\n ) external payable returns (uint128 pendingShareAmount);\n\n /// @notice Emits new shares for the given identifier based on the provided NAV per share.\n /// @param depositAssetId Identifier of the deposit asset for which shares should be issued\n /// @param nowIssueEpochId The epoch for which shares will be issued.\n /// @param navPoolPerShare Total value of assets of the share class per share\n function issueShares(\n PoolId poolId,\n ShareClassId id,\n AssetId depositAssetId,\n uint32 nowIssueEpochId,\n D18 navPoolPerShare\n ) external payable returns (uint128 issuedShareAmount, uint128 depositAssetAmount, uint128 depositPoolAmount);\n\n /// @notice Take back shares for the given identifier based on the provided NAV per share.\n /// deposit asset id.\n /// @param payoutAssetId Identifier of the asset for which all requests want to exchange their share class tokens\n /// @param nowRevokeEpochId The epoch for which shares will be issued.\n /// @param navPoolPerShare Total value of assets of the share class per share\n function revokeShares(\n PoolId poolId,\n ShareClassId scId,\n AssetId payoutAssetId,\n uint32 nowRevokeEpochId,\n D18 navPoolPerShare\n ) external payable returns (uint128 revokedShareAmount, uint128 payoutAssetAmount, uint128 payoutPoolAmount);\n\n /// @notice Tells the BalanceSheet to issue/revoke shares.\n function triggerIssueShares(uint16 centrifugeId, PoolId poolId, ShareClassId scId, address who, uint128 shares)\n external\n payable;\n\n /// @notice Tell the BalanceSheet to send a message back with the queued issued/revoked shares.\n function triggerSubmitQueuedShares(uint16 centrifugeId, PoolId poolId, ShareClassId scId) external payable;\n\n /// @notice Tell the BalanceSheet to send a message back with the queued deposits/withdrawals.\n /// @param assetId Identifier of the asset which has queued deposits/withdrawals\n function triggerSubmitQueuedAssets(PoolId poolId, ShareClassId scId, AssetId assetId) external payable;\n\n /// @notice Tell the BalanceSheet to enable or disable the shares queue.\n function setQueue(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bool enabled) external payable;\n\n /// @notice Update remotely a restriction.\n /// @param centrifugeId Chain where CV instance lives.\n /// @param payload content of the restriction update to execute.\n function updateRestriction(PoolId poolId, ShareClassId scId, uint16 centrifugeId, bytes calldata payload)\n external\n payable;\n\n /// @notice Update remotely an existing vault.\n /// @param centrifugeId Chain where CV instance lives.\n /// @param target contract where to execute in CV. Check IUpdateContract interface.\n /// @param payload content of the update to execute.\n function updateContract(\n PoolId poolId,\n ShareClassId scId,\n uint16 centrifugeId,\n bytes32 target,\n bytes calldata payload\n ) external payable;\n\n /// @notice Update the price per share of a share class\n /// @param scId The share class identifier\n /// @param pricePoolPerShare The new price per share\n function updatePricePerShare(PoolId poolId, ShareClassId scId, D18 pricePoolPerShare) external payable;\n\n /// @notice Create a new holding associated to the asset in a share class.\n /// It will register the different accounts used for holdings.\n /// The accounts have to be created beforehand.\n /// The same account can be used for different kinds.\n /// e.g.: The equity, gain, and loss account can be the same account.\n /// They can also be shared across assets.\n /// e.g.: All assets can use the same equity account.\n /// @param valuation Used to transform between payment assets and pool currency\n /// @param assetAccount Used to track the asset value\n /// @param equityAccount Used to track the equity value\n /// @param gainAccount Used to track the gain value\n /// @param lossAccount Used to track the loss value\n function createHolding(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n IERC7726 valuation,\n AccountId assetAccount,\n AccountId equityAccount,\n AccountId gainAccount,\n AccountId lossAccount\n ) external payable;\n\n /// @notice Create a new liablity associated to the asset in a share class.\n /// It will register the different accounts used for holdings.\n /// The accounts have to be created beforehand.\n /// @param valuation Used to transform between the holding asset and pool currency\n /// @param expenseAccount Used to track the expense value\n /// @param liabilityAccount Used to track the liability value\n function createLiability(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n IERC7726 valuation,\n AccountId expenseAccount,\n AccountId liabilityAccount\n ) external payable;\n\n /// @notice Updates the pool currency value of this holding based of the associated valuation.\n function updateHoldingValue(PoolId poolId, ShareClassId scId, AssetId assetId) external payable;\n\n /// @notice Updates the valuation used by a holding\n /// @param valuation Used to transform between the holding asset and pool currency\n function updateHoldingValuation(PoolId poolId, ShareClassId scId, AssetId assetId, IERC7726 valuation)\n external\n payable;\n\n /// @notice Set an account of a holding\n function setHoldingAccountId(PoolId poolId, ShareClassId scId, AssetId assetId, uint8 kind, AccountId accountId)\n external\n payable;\n\n /// @notice Creates an account\n /// @param accountId Then new AccountId used\n /// @param isDebitNormal Determines if the account should be used as debit-normal or credit-normal\n function createAccount(PoolId poolId, AccountId accountId, bool isDebitNormal) external payable;\n\n /// @notice Attach custom data to an account\n function setAccountMetadata(PoolId poolId, AccountId account, bytes calldata metadata) external payable;\n\n /// @notice Perform an accounting entries update.\n function updateJournal(PoolId poolId, JournalEntry[] memory debits, JournalEntry[] memory credits) external;\n}\n" + }, + "src/hub/interfaces/IHubRegistry.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IERC6909Decimals} from \"src/misc/interfaces/IERC6909.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {IShareClassManager} from \"src/hub/interfaces/IShareClassManager.sol\";\n\ninterface IHubRegistry is IERC6909Decimals {\n event NewAsset(AssetId indexed assetId, uint8 decimals);\n event NewPool(PoolId poolId, address indexed manager, AssetId indexed currency);\n event UpdateManager(PoolId indexed poolId, address indexed manager, bool canManage);\n event SetMetadata(PoolId indexed poolId, bytes metadata);\n event UpdateDependency(bytes32 indexed what, address dependency);\n event UpdateCurrency(PoolId indexed poolId, AssetId currency);\n\n error NonExistingPool(PoolId id);\n error AssetAlreadyRegistered();\n error PoolAlreadyRegistered();\n error EmptyAccount();\n error EmptyCurrency();\n error EmptyShareClassManager();\n error AssetNotFound();\n\n /// @notice Register a new asset.\n function registerAsset(AssetId assetId, uint8 decimals_) external;\n\n /// @notice Register a new pool.\n function registerPool(PoolId poolId, address manager, AssetId currency) external;\n\n /// @notice allow/disallow an address as a manager for the pool\n function updateManager(PoolId poolId, address newManager, bool canManage) external;\n\n /// @notice sets metadata for this pool\n function setMetadata(PoolId poolId, bytes calldata metadata) external;\n\n /// @notice updates a dependency of the system\n function updateDependency(bytes32 what, address dependency) external;\n\n /// @notice updates the currency of the pool\n function updateCurrency(PoolId poolId, AssetId currency) external;\n\n /// @notice returns the metadata attached to the pool, if any.\n function metadata(PoolId poolId) external view returns (bytes memory);\n\n /// @notice returns the currency of the pool\n function currency(PoolId poolId) external view returns (AssetId);\n\n /// @notice returns the dependency used in the system\n function dependency(bytes32 what) external view returns (address);\n\n /// @notice returns whether the account is a manager\n function manager(PoolId poolId, address who) external view returns (bool);\n\n /// @notice compute a pool ID given an ID postfix\n function poolId(uint16 centrifugeId, uint48 postfix) external view returns (PoolId poolId);\n\n /// @notice returns the decimals for an asset\n function decimals(AssetId assetId) external view returns (uint8);\n\n /// @notice returns the decimals for a pool\n function decimals(PoolId poolId) external view returns (uint8);\n\n /// @notice checks the existence of a pool\n function exists(PoolId poolId) external view returns (bool);\n\n /// @notice checks the existence of an asset\n function isRegistered(AssetId assetId) external view returns (bool);\n}\n" + }, + "src/hub/interfaces/IShareClassManager.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {D18} from \"src/misc/types/D18.sol\";\nimport {IERC7726} from \"src/misc/interfaces/IERC7726.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nstruct EpochRedeemAmounts {\n /// @dev Amount of shares pending to be redeemed at time of epoch\n uint128 pendingShareAmount;\n /// @dev Total approved amount of redeemed share class tokens\n uint128 approvedShareAmount;\n /// @dev Total asset amount of revoked share class tokens\n uint128 payoutAssetAmount;\n /// @dev The amount of pool currency per unit of asset at time of approval\n D18 pricePoolPerAsset;\n /// @dev The amount of pool currency per unit of share at time of revocation\n D18 navPoolPerShare;\n /// @dev block timestamp when shares of epoch were revoked\n uint64 revokedAt;\n}\n\nstruct EpochInvestAmounts {\n /// @dev Total pending asset amount of deposit asset at time of epoch\n uint128 pendingAssetAmount;\n /// @dev Total approved asset amount of deposit asset\n uint128 approvedAssetAmount;\n /// @dev Total approved pool amount of deposit asset\n uint128 approvedPoolAmount;\n /// @dev The amount of pool currency per unit of asset at time of approval\n D18 pricePoolPerAsset;\n /// @dev The amount of pool currency per unit of share at time of issuance\n D18 navPoolPerShare;\n /// @dev block timestamp when shares of epoch were issued\n uint64 issuedAt;\n}\n\nstruct UserOrder {\n /// @dev Pending amount in deposit asset denomination\n uint128 pending;\n /// @dev Index of epoch in which last order was made\n uint32 lastUpdate;\n}\n\nstruct ShareClassMetadata {\n /// @dev The name of the share class token\n string name;\n /// @dev The symbol of the share class token\n string symbol;\n /// @dev The salt of the share class token\n bytes32 salt;\n}\n\nstruct ShareClassMetrics {\n /// @dev Total number of shares\n uint128 totalIssuance;\n /// @dev The latest net asset value per share class token\n D18 navPerShare;\n}\n\nstruct QueuedOrder {\n /// @dev Whether the user requested a cancellation which is now queued\n bool isCancelling;\n /// @dev The queued increased request amount\n uint128 amount;\n}\n\nenum RequestType {\n /// @dev Whether the request is a deposit one\n Deposit,\n /// @dev Whether the request is a redeem one\n Redeem\n}\n\nstruct EpochId {\n uint32 deposit;\n uint32 redeem;\n uint32 issue;\n uint32 revoke;\n}\n\ninterface IShareClassManager {\n /// Events\n event AddShareClass(\n PoolId indexed poolId, ShareClassId indexed scId, uint32 indexed index, string name, string symbol, bytes32 salt\n );\n event UpdateMetadata(PoolId indexed poolId, ShareClassId indexed scId, string name, string symbol);\n event ApproveDeposits(\n PoolId indexed poolId,\n ShareClassId indexed scId,\n AssetId indexed depositAssetId,\n uint32 epoch,\n uint128 approvedPoolAmount,\n uint128 approvedAssetAmount,\n uint128 pendingAssetAmount\n );\n event ApproveRedeems(\n PoolId indexed poolId,\n ShareClassId indexed scId,\n AssetId indexed payoutAssetId,\n uint32 epoch,\n uint128 approvedShareAmount,\n uint128 pendingShareAmount\n );\n event IssueShares(\n PoolId indexed poolId,\n ShareClassId indexed scId,\n AssetId indexed depositAssetId,\n uint32 epoch,\n D18 navPoolPerShare,\n D18 navAssetPerShare,\n uint128 issuedShareAmount\n );\n event RemoteIssueShares(PoolId indexed poolId, ShareClassId indexed scId, uint128 issuedShareAmount);\n event RevokeShares(\n PoolId indexed poolId,\n ShareClassId indexed scId,\n AssetId indexed payoutAssetId,\n uint32 epoch,\n D18 navPoolPerShare,\n D18 navAssetPerShare,\n uint128 revokedShareAmount,\n uint128 revokedAssetAmount,\n uint128 revokedPoolAmount\n );\n event RemoteRevokeShares(PoolId indexed poolId, ShareClassId indexed scId, uint128 revokedAssetAmount);\n event ClaimDeposit(\n PoolId indexed poolId,\n ShareClassId indexed scId,\n uint32 epoch,\n bytes32 investor,\n AssetId indexed depositAssetId,\n uint128 paymentAssetAmount,\n uint128 pendingAssetAmount,\n uint128 claimedShareAmount,\n uint64 issuedAt\n );\n event ClaimRedeem(\n PoolId indexed poolId,\n ShareClassId indexed scId,\n uint32 epoch,\n bytes32 investor,\n AssetId indexed payoutAssetId,\n uint128 paymentShareAmount,\n uint128 pendingShareAmount,\n uint128 claimedAssetAmount,\n uint64 revokedAt\n );\n event AddShareClass(PoolId indexed poolId, ShareClassId indexed scId, uint32 indexed index);\n event UpdateShareClass(PoolId indexed poolId, ShareClassId indexed scId, D18 navPoolPerShare);\n event UpdateDepositRequest(\n PoolId indexed poolId,\n ShareClassId indexed scId,\n AssetId indexed depositAssetId,\n uint32 epoch,\n bytes32 investor,\n uint128 pendingUserAssetAmount,\n uint128 pendingTotalAssetAmount,\n uint128 queuedUserAssetAmount,\n bool pendingCancellation\n );\n event UpdateRedeemRequest(\n PoolId indexed poolId,\n ShareClassId indexed scId,\n AssetId indexed payoutAssetId,\n uint32 epoch,\n bytes32 investor,\n uint128 pendingUserShareAmount,\n uint128 pendingTotalShareAmount,\n uint128 queuedUserShareAmount,\n bool pendingCancellation\n );\n\n /// Errors\n error EpochNotInSequence(uint32 providedEpoch, uint32 nowEpoch);\n error NoOrderFound();\n error InsufficientPending();\n error ApprovalRequired();\n error IssuanceRequired();\n error AlreadyIssued();\n error RevocationRequired();\n error ZeroApprovalAmount();\n error InvalidMetadataSize();\n error InvalidMetadataName();\n error InvalidMetadataSymbol();\n error InvalidSalt();\n error AlreadyUsedSalt();\n error RevokeMoreThanIssued();\n error PoolMissing();\n error ShareClassNotFound();\n error EpochNotFound();\n error DecreaseMoreThanIssued();\n error CancellationQueued();\n\n /// Functions\n\n /// @notice Creates or updates a request to deposit (exchange) an asset amount for share class tokens.\n ///\n /// @param poolId Identifier of the pool\n /// @param scId Identifier of the share class\n /// @param amount Asset token amount which is deposited\n /// @param investor Centrifuge Vault address of the entity which is depositing\n /// @param depositAssetId Identifier of the asset which the investor used for their deposit request\n function requestDeposit(PoolId poolId, ShareClassId scId, uint128 amount, bytes32 investor, AssetId depositAssetId)\n external;\n\n /// @notice Cancels a pending deposit request.\n ///\n /// @param poolId Identifier of the pool\n /// @param scId Identifier of the share class\n /// @param investor Centrifuge Vault address of the entity which is cancelling\n /// @param depositAssetId Identifier of the asset which the investor used for their deposit request\n /// @return cancelledAssetAmount The deposit amount which was previously pending and is now cancelled. This amount\n /// was not potentially (partially) swapped to the pool amount in case the deposit asset cannot be exchanged 1:1\n /// into the pool token\n function cancelDepositRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId depositAssetId)\n external\n returns (uint128 cancelledAssetAmount);\n\n /// @notice Creates or updates a request to redeem (exchange) share class tokens for some asset.\n ///\n /// @param poolId Identifier of the pool\n /// @param scId Identifier of the share class\n /// @param amount Share class token amount which should be redeemed\n /// @param investor Centrifuge Vault address of the entity which is redeeming\n /// @param payoutAssetId Identifier of the asset which the investor eventually receives back for their redeemed\n /// share class tokens\n function requestRedeem(PoolId poolId, ShareClassId scId, uint128 amount, bytes32 investor, AssetId payoutAssetId)\n external;\n\n /// @notice Cancels a pending redeem request.\n ///\n /// @param poolId Identifier of the pool\n /// @param scId Identifier of the share class\n /// @param investor Centrifuge Vault address of the entity which is cancelling\n /// @param payoutAssetId Identifier of the asset which the investor eventually receives back for their redeemed\n /// share class tokens\n /// @return cancelledShareAmount The redeem amount which was previously pending and is now cancelled\n function cancelRedeemRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId payoutAssetId)\n external\n returns (uint128 cancelledShareAmount);\n\n /// @notice Approves an asset amount of all deposit requests for the given triplet of pool id, share class id and\n /// deposit asset id.\n /// @dev nowDepositEpochId MUST be called sequentially.\n ///\n /// @param poolId Identifier of the pool\n /// @param scId Identifier of the share class\n /// @param depositAssetId Identifier of the asset locked for the deposit request\n /// @param nowDepositEpochId The epoch for which shares will be approved.\n /// @param approvedAssetAmount Amount of assets that will be approved for deposit\n /// @param pricePoolPerAsset Amount of pool unit one gets for a unit of asset\n /// @return pendingAssetAmount Amount of assets still pending for deposit\n /// @return approvedPoolAmount Amount of pool units approved for deposit\n function approveDeposits(\n PoolId poolId,\n ShareClassId scId,\n AssetId depositAssetId,\n uint32 nowDepositEpochId,\n uint128 approvedAssetAmount,\n D18 pricePoolPerAsset\n ) external returns (uint128 pendingAssetAmount, uint128 approvedPoolAmount);\n\n /// @notice Approves a share class token amount of all redeem requests for the given triplet of pool id, share class\n /// id and payout asset id.\n /// @dev nowRedeemEpochId MUST be called sequentially.\n ///\n /// @param poolId Identifier of the pool\n /// @param scId Identifier of the share class\n /// @param payoutAssetId Identifier of the asset for which all requests want to exchange their share class tokens\n /// for\n /// @param nowRedeemEpochId The epoch for which shares will be approved.\n /// @param approvedShareAmount Amount of shares that will be approved for redemption\n /// @param pricePoolPerAsset Amount of pool unit one gets for a unit of asset\n /// @return pendingShareAmount Sum of redemption request amounts in share class token amount which was not approved\n function approveRedeems(\n PoolId poolId,\n ShareClassId scId,\n AssetId payoutAssetId,\n uint32 nowRedeemEpochId,\n uint128 approvedShareAmount,\n D18 pricePoolPerAsset\n ) external returns (uint128 pendingShareAmount);\n\n /// @notice Emits new shares for the given identifier based on the provided NAV per share.\n /// @dev nowIssueEpochId MUST be called sequentially.\n ///\n /// @param poolId Identifier of the pool\n /// @param scId Identifier of the share class\n /// @param depositAssetId Identifier of the deposit asset for which shares should be issued\n /// @param nowIssueEpochId The epoch for which shares will be issued.\n /// @param navPoolPerShare The nav per share value of the share class (in the pool currency denomination. Conversion\n /// to asset price is done onchain based on the valuation of the asset at approval)\n /// @return issuedShareAmount Amount of shares that have been issued\n function issueShares(\n PoolId poolId,\n ShareClassId scId,\n AssetId depositAssetId,\n uint32 nowIssueEpochId,\n D18 navPoolPerShare\n ) external returns (uint128 issuedShareAmount, uint128 depositAssetAmount, uint128 depositPoolAmount);\n\n /// @notice Take back shares for the given identifier based on the provided NAV per share.\n /// @dev nowRevokeEpochId MUST be called sequentially.\n ///\n /// @param poolId Identifier of the pool\n /// @param scId Identifier of the share class\n /// @param payoutAssetId Identifier of the payout asset\n /// @param nowRevokeEpochId The epoch for which shares will be revoked.\n /// @param navPoolPerShare The nav per share value of the share class (in the pool currency denomination. Conversion\n /// to asset price is done onchain based on the valuation of the asset at approval)\n /// @return revokedShareAmount Amount of shares that have been revoked\n /// @return payoutAssetAmount Converted amount of payout asset based on number of revoked shares\n /// @return payoutPoolAmount Converted amount of pool currency based on number of revoked shares\n function revokeShares(\n PoolId poolId,\n ShareClassId scId,\n AssetId payoutAssetId,\n uint32 nowRevokeEpochId,\n D18 navPoolPerShare\n ) external returns (uint128 revokedShareAmount, uint128 payoutAssetAmount, uint128 payoutPoolAmount);\n\n /// @notice Collects shares for an investor after their deposit request was (partially) approved and new shares were\n /// issued.\n ///\n /// @param poolId Identifier of the pool\n /// @param scId Identifier of the share class\n /// @param investor Centrifuge Vault address of the recipient of the claimed share class tokens\n /// @param depositAssetId Identifier of the asset which the investor used for their deposit request\n /// @return payoutShareAmount Amount of shares which the investor receives\n /// @return paymentAssetAmount Amount of deposit asset which was taken as payment\n /// @return cancelledAssetAmount Amount of deposit asset which was cancelled due to being queued\n /// @return canClaimAgain Whether another call to claimRedeem is needed until investor has fully claimed investments\n function claimDeposit(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId depositAssetId)\n external\n returns (\n uint128 payoutShareAmount,\n uint128 paymentAssetAmount,\n uint128 cancelledAssetAmount,\n bool canClaimAgain\n );\n\n /// @notice Collects an asset amount for an investor after their redeem request was (partially) approved and shares\n /// were revoked.\n ///\n /// @param poolId Identifier of the pool\n /// @param scId Identifier of the share class\n /// @param investor Centrifuge Vault address of the recipient of the claimed asset amount\n /// @param payoutAssetId Identifier of the asset which the investor requested to receive back for their redeemed\n /// shares\n /// @return payoutAssetAmount Amount of payout amount which the investor receives\n /// @return paymentShareAmount Amount of shares which the investor redeemed\n /// @return cancelledShareAmount Amount of shares which were cancelled due to being queued\n /// @return canClaimAgain Whether another call to claimRedeem is needed until investor has fully claimed redemptions\n function claimRedeem(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId payoutAssetId)\n external\n returns (\n uint128 payoutAssetAmount,\n uint128 paymentShareAmount,\n uint128 cancelledShareAmount,\n bool canClaimAgain\n );\n\n /// @notice Increases the share class issuance\n ///\n /// @param poolId Identifier of the pool\n /// @param scId Identifier of the share class\n /// @param amount The amount to increase the share class issuance by\n function increaseShareClassIssuance(PoolId poolId, ShareClassId scId, uint128 amount) external;\n\n /// @notice Decreases the share class issuance\n ///\n /// @param poolId Identifier of the pool\n /// @param scId Identifier of the share class\n /// @param amount The amount to decrease the share class issuance by\n function decreaseShareClassIssuance(PoolId poolId, ShareClassId scId, uint128 amount) external;\n\n /// @notice Adds a new share class to the given pool.\n ///\n /// @param poolId Identifier of the pool\n /// @param name The name of the share class\n /// @param symbol The symbol of the share class\n /// @param salt The salt used for deploying the share class tokens\n /// @return scId Identifier of the newly added share class\n function addShareClass(PoolId poolId, string calldata name, string calldata symbol, bytes32 salt)\n external\n returns (ShareClassId scId);\n\n /// @notice Updates the price pool unit per share unit of a share class\n ///\n /// @param poolId Identifier of the pool\n /// @param scId Identifier of the share class\n /// @param pricePoolPerShare The price per share of the share class (in the pool currency denomination)\n function updatePricePerShare(PoolId poolId, ShareClassId scId, D18 pricePoolPerShare) external;\n\n /// @notice Updates the metadata of a share class.\n ///\n /// @param poolId Identifier of the pool\n /// @param scId Identifier of the share class\n /// @param name The name of the share class\n /// @param symbol The symbol of the share class\n function updateMetadata(PoolId poolId, ShareClassId scId, string calldata name, string calldata symbol) external;\n\n /// @notice Returns the number of share classes for the given pool\n ///\n /// @param poolId Identifier of the pool in question\n /// @return count Number of share classes for the given pool\n function shareClassCount(PoolId poolId) external view returns (uint32 count);\n\n /// @notice Checks the existence of a share class.\n ///\n /// @param poolId Identifier of the pool\n /// @param scId Identifier of the share class\n function exists(PoolId poolId, ShareClassId scId) external view returns (bool);\n\n /// @notice Returns the current ongoing epoch id for deposits\n ///\n /// @param scId Identifier of the share class\n /// @param depositAssetId AssetId of the payment asset\n function nowDepositEpoch(ShareClassId scId, AssetId depositAssetId) external view returns (uint32);\n\n /// @notice Returns the epoch for which will be issued next\n ///\n /// @param scId Identifier of the share class\n /// @param depositAssetId AssetId of the payment asset\n function nowIssueEpoch(ShareClassId scId, AssetId depositAssetId) external view returns (uint32);\n\n /// @notice Returns the current ongoing epoch id for deposits\n ///\n /// @param scId Identifier of the share class\n /// @param payoutAssetId AssetId of the payment asset\n function nowRedeemEpoch(ShareClassId scId, AssetId payoutAssetId) external view returns (uint32);\n\n /// @notice Returns the epoch for which will be revoked next\n ///\n /// @param scId Identifier of the share class\n /// @param depositAssetId AssetId of the payment asset\n function nowRevokeEpoch(ShareClassId scId, AssetId depositAssetId) external view returns (uint32);\n\n /// @notice Returns an upper bound for possible calls to `function claimDeposit(..)`\n ///\n /// @param scId Identifier of the share class\n /// @param investor Recipient of the share class tokens\n /// @param depositAssetId AssetId of the payment asset\n function maxDepositClaims(ShareClassId scId, bytes32 investor, AssetId depositAssetId)\n external\n view\n returns (uint32 maxClaims);\n\n /// @notice Returns an upper bound for possible calls to `function claimRedeem(..)`\n ///\n /// @param scId Identifier of the share class\n /// @param investor Recipient of the payout assets\n /// @param payoutAssetId AssetId of the payout asset\n function maxRedeemClaims(ShareClassId scId, bytes32 investor, AssetId payoutAssetId)\n external\n view\n returns (uint32 maxClaims);\n\n /// @notice Exposes relevant metrics for a share class\n ///\n /// @return totalIssuance The total number of shares known to the CP side\n /// @return pricePoolPerShare The amount of pool units per unit share\n function metrics(ShareClassId scId) external view returns (uint128 totalIssuance, D18 pricePoolPerShare);\n\n /// @notice Determines the next share class id for the given pool.\n ///\n /// @param poolId Identifier of the pool\n /// @return scId Identifier of the next share class\n function previewNextShareClassId(PoolId poolId) external view returns (ShareClassId scId);\n\n /// @notice Determines the share class id for the given pool and index.\n ///\n /// @param poolId Identifier of the pool\n /// @param index The pool-internal index of the share class id\n /// @return scId Identifier of the underlying share class\n function previewShareClassId(PoolId poolId, uint32 index) external pure returns (ShareClassId scId);\n\n /// @notice returns The metadata of the share class.\n ///\n /// @param scId Identifier of the share class\n /// @return name The registered name of the share class token\n /// @return symbol The registered symbol of the share class token\n /// @return salt The registered salt of the share class token, used for deterministic deployments\n function metadata(ShareClassId scId) external returns (string memory name, string memory symbol, bytes32 salt);\n}\n" + }, + "src/misc/Auth.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IAuth} from \"src/misc/interfaces/IAuth.sol\";\n\n/// @title Auth\n/// @notice Simple authentication pattern\n/// @author Based on code from https://github.com/makerdao/dss\nabstract contract Auth is IAuth {\n /// @inheritdoc IAuth\n mapping(address => uint256) public wards;\n\n constructor(address initialWard) {\n wards[initialWard] = 1;\n emit Rely(initialWard);\n }\n\n /// @dev Check if the msg.sender has permissions\n modifier auth() {\n require(wards[msg.sender] == 1, NotAuthorized());\n _;\n }\n\n /// @inheritdoc IAuth\n function rely(address user) public auth {\n wards[user] = 1;\n emit Rely(user);\n }\n\n /// @inheritdoc IAuth\n function deny(address user) public auth {\n wards[user] = 0;\n emit Deny(user);\n }\n}\n" + }, + "src/misc/BaseValuation.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IBaseValuation} from \"src/misc/interfaces/IBaseValuation.sol\";\nimport {IERC6909Decimals} from \"src/misc/interfaces/IERC6909.sol\";\n\nimport {Auth} from \"src/misc/Auth.sol\";\n\nabstract contract BaseValuation is Auth, IBaseValuation {\n /// @notice ERC6909 dependency.\n IERC6909Decimals public erc6909;\n\n constructor(IERC6909Decimals erc6909_, address deployer) Auth(deployer) {\n erc6909 = erc6909_;\n }\n\n /// @inheritdoc IBaseValuation\n function file(bytes32 what, address data) external auth {\n if (what == \"erc6909\") erc6909 = IERC6909Decimals(data);\n else revert FileUnrecognizedParam();\n\n emit File(what, data);\n }\n\n /// @notice Obtain the correct decimals given an asset address\n function _getDecimals(address asset) internal view returns (uint8) {\n return erc6909.decimals(uint160(asset));\n }\n}\n" + }, + "src/misc/ERC20.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {EIP712Lib} from \"src/misc/libraries/EIP712Lib.sol\";\nimport {SignatureLib} from \"src/misc/libraries/SignatureLib.sol\";\n\nimport {IERC20, IERC20Metadata, IERC20Permit} from \"src/misc/interfaces/IERC20.sol\";\n\n/// @title ERC20\n/// @notice Standard ERC-20 implementation, with mint/burn functionality and permit logic.\n/// @author Modified from https://github.com/makerdao/xdomain-dss/blob/master/src/Dai.sol\ncontract ERC20 is Auth, IERC20Metadata, IERC20Permit {\n error FileUnrecognizedParam();\n\n /// @inheritdoc IERC20Metadata\n string public name;\n /// @inheritdoc IERC20Metadata\n string public symbol;\n /// @inheritdoc IERC20Metadata\n uint8 public immutable decimals;\n /// @inheritdoc IERC20\n uint256 public totalSupply;\n\n mapping(address => uint256) private balances;\n\n /// @inheritdoc IERC20\n mapping(address => mapping(address => uint256)) public allowance;\n /// @inheritdoc IERC20Permit\n mapping(address => uint256) public nonces;\n\n // --- EIP712 ---\n bytes32 private immutable nameHash;\n bytes32 private immutable versionHash;\n uint256 public immutable deploymentChainId;\n bytes32 private immutable _DOMAIN_SEPARATOR;\n bytes32 public constant PERMIT_TYPEHASH =\n keccak256(\"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\");\n\n // --- Events ---\n event File(bytes32 indexed what, string data);\n\n constructor(uint8 decimals_) Auth(msg.sender) {\n decimals = decimals_;\n\n nameHash = keccak256(bytes(\"Centrifuge\"));\n versionHash = keccak256(bytes(\"1\"));\n deploymentChainId = block.chainid;\n _DOMAIN_SEPARATOR = EIP712Lib.calculateDomainSeparator(nameHash, versionHash);\n }\n\n function _balanceOf(address user) internal view virtual returns (uint256) {\n return balances[user];\n }\n\n /// @inheritdoc IERC20\n function balanceOf(address user) public view virtual returns (uint256) {\n return _balanceOf(user);\n }\n\n function _setBalance(address user, uint256 value) internal virtual {\n balances[user] = value;\n }\n\n /// @inheritdoc IERC20Permit\n function DOMAIN_SEPARATOR() public view returns (bytes32) {\n return block.chainid == deploymentChainId\n ? _DOMAIN_SEPARATOR\n : EIP712Lib.calculateDomainSeparator(nameHash, versionHash);\n }\n\n // --- Administration ---\n function file(bytes32 what, string memory data) public virtual auth {\n if (what == \"name\") name = data;\n else if (what == \"symbol\") symbol = data;\n else revert FileUnrecognizedParam();\n emit File(what, data);\n }\n\n // --- ERC20 Mutations ---\n /// @inheritdoc IERC20\n function transfer(address to, uint256 value) public virtual returns (bool) {\n require(to != address(0) && to != address(this), InvalidAddress());\n uint256 balance = balanceOf(msg.sender);\n require(balance >= value, InsufficientBalance());\n\n unchecked {\n _setBalance(msg.sender, balance - value);\n // note: we don't need an overflow check here b/c sum of all balances == totalSupply\n _setBalance(to, _balanceOf(to) + value);\n }\n\n emit Transfer(msg.sender, to, value);\n\n return true;\n }\n\n /// @inheritdoc IERC20\n function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {\n return _transferFrom(msg.sender, from, to, value);\n }\n\n function _transferFrom(address sender, address from, address to, uint256 value) internal virtual returns (bool) {\n require(to != address(0) && to != address(this), InvalidAddress());\n uint256 balance = balanceOf(from);\n require(balance >= value, InsufficientBalance());\n\n if (from != sender) {\n uint256 allowed = allowance[from][sender];\n if (allowed != type(uint256).max) {\n require(allowed >= value, InsufficientAllowance());\n unchecked {\n allowance[from][sender] = allowed - value;\n }\n }\n }\n\n unchecked {\n _setBalance(from, balance - value);\n // note: we don't need an overflow check here b/c sum of all balances == totalSupply\n _setBalance(to, _balanceOf(to) + value);\n }\n\n emit Transfer(from, to, value);\n\n return true;\n }\n\n /// @inheritdoc IERC20\n function approve(address spender, uint256 value) external returns (bool) {\n allowance[msg.sender][spender] = value;\n\n emit Approval(msg.sender, spender, value);\n\n return true;\n }\n\n // --- Mint/Burn ---\n function mint(address to, uint256 value) public virtual auth {\n require(to != address(0) && to != address(this), InvalidAddress());\n unchecked {\n // We don't need an overflow check here b/c balances[to] <= totalSupply\n // and there is an overflow check below\n _setBalance(to, _balanceOf(to) + value);\n }\n totalSupply += value;\n\n emit Transfer(address(0), to, value);\n }\n\n function burn(address from, uint256 value) public virtual auth {\n uint256 balance = balanceOf(from);\n require(balance >= value, InsufficientBalance());\n\n if (from != msg.sender) {\n uint256 allowed = allowance[from][msg.sender];\n if (allowed != type(uint256).max) {\n require(allowed >= value, InsufficientAllowance());\n\n unchecked {\n allowance[from][msg.sender] = allowed - value;\n }\n }\n }\n\n unchecked {\n // We don't need overflow checks b/c require(balance >= value) and balance <= totalSupply\n _setBalance(from, balance - value);\n totalSupply -= value;\n }\n\n emit Transfer(from, address(0), value);\n }\n\n // --- Approve by signature ---\n function permit(address owner, address spender, uint256 value, uint256 deadline, bytes memory signature) public {\n require(block.timestamp <= deadline, PermitExpired());\n\n uint256 nonce;\n unchecked {\n nonce = nonces[owner]++;\n }\n\n bytes32 digest = keccak256(\n abi.encodePacked(\n \"\\x19\\x01\",\n DOMAIN_SEPARATOR(),\n keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonce, deadline))\n )\n );\n\n require(SignatureLib.isValidSignature(owner, digest, signature), InvalidPermit());\n\n allowance[owner][spender] = value;\n emit Approval(owner, spender, value);\n }\n\n /// @inheritdoc IERC20Permit\n function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)\n external\n {\n permit(owner, spender, value, deadline, abi.encodePacked(r, s, v));\n }\n}\n" + }, + "src/misc/IdentityValuation.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {d18} from \"src/misc/types/D18.sol\";\nimport {IERC7726} from \"src/misc/interfaces/IERC7726.sol\";\nimport {IIdentityValuation} from \"src/misc/interfaces/IIdentityValuation.sol\";\nimport {IERC6909Decimals} from \"src/misc/interfaces/IERC6909.sol\";\nimport {BaseValuation} from \"src/misc/BaseValuation.sol\";\n\nimport {PricingLib} from \"src/common/libraries/PricingLib.sol\";\n\ncontract IdentityValuation is BaseValuation, IIdentityValuation {\n constructor(IERC6909Decimals erc6909, address deployer) BaseValuation(erc6909, deployer) {}\n\n /// @inheritdoc IERC7726\n function getQuote(uint256 baseAmount, address base, address quote) external view returns (uint256 quoteAmount) {\n return PricingLib.convertWithPrice(baseAmount, _getDecimals(base), _getDecimals(quote), d18(1e18));\n }\n}\n" + }, + "src/misc/Multicall.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.28;\n\n// NOTE: This file has warning disabled due https://github.com/ethereum/solidity/issues/14359\n// If perform any change on it, please ensure no other warnings appears\n\nimport {IMulticall} from \"src/misc/interfaces/IMulticall.sol\";\nimport {ReentrancyProtection} from \"src/misc/ReentrancyProtection.sol\";\n\nabstract contract Multicall is ReentrancyProtection, IMulticall {\n function multicall(bytes[] calldata data) public payable virtual protected {\n uint256 totalBytes = data.length;\n for (uint256 i; i < totalBytes; ++i) {\n (bool success, bytes memory returnData) = address(this).delegatecall(data[i]);\n if (!success) {\n uint256 length = returnData.length;\n require(length != 0, CallFailedWithEmptyRevert());\n\n assembly (\"memory-safe\") {\n revert(add(32, returnData), length)\n }\n }\n }\n }\n}\n" + }, + "src/misc/Recoverable.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {IERC6909} from \"src/misc/interfaces/IERC6909.sol\";\nimport {SafeTransferLib} from \"src/misc/libraries/SafeTransferLib.sol\";\n\nimport {IRecoverable, ETH_ADDRESS} from \"src/misc/interfaces/IRecoverable.sol\";\n\nabstract contract Recoverable is Auth, IRecoverable {\n /// @inheritdoc IRecoverable\n function recoverTokens(address token, address receiver, uint256 amount) public auth {\n if (token == ETH_ADDRESS) {\n SafeTransferLib.safeTransferETH(receiver, amount);\n } else {\n SafeTransferLib.safeTransfer(token, receiver, amount);\n }\n }\n\n /// @inheritdoc IRecoverable\n function recoverTokens(address token, uint256 tokenId, address receiver, uint256 amount) external auth {\n if (tokenId == 0) {\n recoverTokens(token, receiver, amount);\n } else {\n IERC6909(token).transfer(receiver, tokenId, amount);\n }\n }\n}\n" + }, + "src/misc/ReentrancyProtection.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.28;\n\n// NOTE: This file has warning disabled due https://github.com/ethereum/solidity/issues/14359\n// If perform any change on it, please ensure no other warnings appears\n\nabstract contract ReentrancyProtection {\n /// @notice Dispatched when there is a re-entrancy issue\n error UnauthorizedSender();\n\n address private transient _initiator;\n\n /// @dev The method is protected for reentrancy issues.\n modifier protected() {\n if (_initiator == address(0)) {\n // Single call re-entrancy lock\n _initiator = msg.sender;\n _;\n _initiator = address(0);\n } else {\n // Multicall re-entrancy lock\n require(msg.sender == _initiator, UnauthorizedSender());\n _;\n }\n }\n}\n" + }, + "src/misc/interfaces/IAuth.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\ninterface IAuth {\n event Rely(address indexed user);\n event Deny(address indexed user);\n\n error NotAuthorized();\n\n /// @notice Returns whether the target is a ward (has admin access)\n function wards(address target) external view returns (uint256);\n\n /// @notice Make user a ward (give them admin access)\n function rely(address user) external;\n\n /// @notice Remove user as a ward (remove admin access)\n function deny(address user) external;\n}\n" + }, + "src/misc/interfaces/IBaseValuation.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IERC7726} from \"src/misc/interfaces/IERC7726.sol\";\n\n/// Provides a base implementation for all ERC7726 valuation in the system\ninterface IBaseValuation is IERC7726 {\n /// @notice Emitted when a call to `file()` was performed.\n event File(bytes32 indexed what, address addr);\n\n /// @notice Dispatched when the `what` parameter of `file()` is not supported by the implementation.\n error FileUnrecognizedParam();\n\n /// @notice Updates a contract parameter.\n /// @param what Name of the parameter to update.\n /// Accepts a `bytes32` representation of 'assetRegistry' string value.\n /// @param data New value given to the `what` parameter\n function file(bytes32 what, address data) external;\n}\n" + }, + "src/misc/interfaces/IERC20.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\n/// @title IERC20\n/// @dev Interface of the ERC20 standard as defined in the EIP.\n/// @author Modified from OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)\ninterface IERC20 {\n error InvalidAddress();\n error InsufficientBalance();\n error InsufficientAllowance();\n\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n error PermitExpired();\n error InvalidPermit();\n\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)\n external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\ninterface IERC20Wrapper {\n /**\n * @dev Returns the address of the underlying ERC-20 token that is being wrapped.\n */\n function underlying() external view returns (address);\n\n /**\n * @dev Allow a user to deposit underlying tokens and mint the corresponding number of wrapped tokens.\n */\n function depositFor(address account, uint256 value) external returns (bool);\n\n /**\n * @dev Allow a user to burn a number of wrapped tokens and withdraw the corresponding number of underlying tokens.\n */\n function withdrawTo(address account, uint256 value) external returns (bool);\n}\n" + }, + "src/misc/interfaces/IERC6909.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IERC165} from \"forge-std/interfaces/IERC165.sol\";\n\ninterface IERC6909 is IERC165 {\n error EmptyOwner();\n error EmptyAmount();\n error InvalidTokenId();\n error InsufficientBalance(address owner, uint256 tokenId);\n error InsufficientAllowance(address sender, uint256 tokenId);\n\n event OperatorSet(address indexed owner, address indexed operator, bool approved);\n event Approval(address indexed owner, address indexed spender, uint256 indexed tokenId, uint256 amount);\n event Transfer(address caller, address indexed from, address indexed to, uint256 indexed tokenId, uint256 amount);\n\n /// @notice Owner balance of a tokenId.\n /// @param owner The address of the owner.\n /// @param tokenId The id of the token.\n /// @return amount The balance of the token.\n function balanceOf(address owner, uint256 tokenId) external view returns (uint256 amount);\n\n /// @notice Spender allowance of a tokenId.\n /// @param owner The address of the owner.\n /// @param spender The address of the spender.\n /// @param tokenId The id of the token.\n /// @return amount The allowance of the token.\n function allowance(address owner, address spender, uint256 tokenId) external view returns (uint256 amount);\n\n /// @notice Checks if a spender is approved by an owner as an operator.\n /// @param owner The address of the owner.\n /// @param spender The address of the spender.\n /// @return approved The approval status.\n function isOperator(address owner, address spender) external view returns (bool approved);\n\n /// @notice Transfers an amount of a tokenId from the caller to a receiver.\n /// @param receiver The address of the receiver.\n /// @param tokenId The id of the token.\n /// @param amount The amount of the token.\n /// @return bool True, always, unless the function reverts.\n function transfer(address receiver, uint256 tokenId, uint256 amount) external returns (bool);\n\n /// @notice Transfers an amount of a tokenId from a sender to a receiver.\n /// @param sender The address of the sender.\n /// @param receiver The address of the receiver.\n /// @param tokenId The id of the token.\n /// @param amount The amount of the token.\n /// @return bool True, always, unless the function reverts.\n function transferFrom(address sender, address receiver, uint256 tokenId, uint256 amount) external returns (bool);\n\n /// @notice Approves an amount of a tokenId to a spender.\n /// @param spender The address of the spender.\n /// @param tokenId The id of the token.\n /// @param amount The amount of the token.\n /// @return bool True, always.\n function approve(address spender, uint256 tokenId, uint256 amount) external returns (bool);\n\n /// @notice Sets or removes an operator for the caller.\n /// @param operator The address of the operator.\n /// @param approved The approval status.\n /// @return bool True, always.\n function setOperator(address operator, bool approved) external returns (bool);\n}\n\ninterface IERC6909URIExt {\n event TokenURISet(uint256 indexed tokenId, string uri);\n event ContractURISet(address indexed target, string uri);\n\n error EmptyURI();\n\n /// @return uri Returns the common token URI.\n function contractURI() external view returns (string memory);\n\n /// @dev Returns empty string if tokenId does not exist.\n /// MAY implemented to throw MissingURI(tokenId) error.\n /// @param tokenId The token to query URI for.\n /// @return uri A string representing the uri for the specific tokenId.\n function tokenURI(uint256 tokenId) external view returns (string memory);\n}\n\ninterface IERC6909NFT is IERC6909, IERC6909URIExt {\n error UnknownTokenId(address owner, uint256 tokenId);\n error LessThanMinimalDecimal(uint8 minimal, uint8 actual);\n\n /// @notice Provide URI for a specific tokenId.\n /// @param tokenId Token Id.\n /// @param URI URI to a document defining the collection as a whole.\n function setTokenURI(uint256 tokenId, string memory URI) external;\n\n /// @dev Optional method to set up the contract URI if needed.\n /// @param URI URI to a document defining the collection as a whole.\n function setContractURI(string memory URI) external;\n\n /// @notice Mint new tokens for a given owner and sets tokenURI.\n /// @dev For non-fungible tokens, call with amount = 1, for fungible it could be any amount.\n /// TokenId is auto incremented by one.\n ///\n /// @param owner Creates supply of a given tokenId by amount for owner.\n /// @param tokenURI URI fortestBurningToken the newly minted token.\n /// @return tokenId Id of the newly minted token.\n function mint(address owner, string memory tokenURI) external returns (uint256 tokenId);\n\n /// @notice Destroy supply of a given tokenId by amount.\n /// @dev The msg.sender MUST be the owner.\n ///\n /// @param tokenId Item which have reduced supply.\n function burn(uint256 tokenId) external;\n}\n\n/// @notice Extension of ERC6909 Standard for tracking total supply\ninterface IERC6909TotalSupplyExt {\n /// @notice The totalSupply for a token id.\n ///\n /// @param tokenId Id of the token\n /// @return supply Total supply for a given `tokenId`\n function totalSupply(uint256 tokenId) external returns (uint256 supply);\n}\n\ninterface IERC6909Decimals {\n /// @notice Used to retrieve the decimals of an asset\n /// @dev address is used but the value corresponds to a AssetId\n function decimals(uint256 assetId) external view returns (uint8);\n}\n\ninterface IERC6909MetadataExt is IERC6909Decimals {\n /// @notice Used to retrieve the decimals of an asset\n /// @dev address is used but the value corresponds to a AssetId\n function decimals(uint256 assetId) external view returns (uint8);\n\n /// @notice Used to retrieve the name of an asset\n /// @dev address is used but the value corresponds to a AssetId\n function name(uint256 assetId) external view returns (string memory);\n\n /// @notice Used to retrieve the symbol of an asset\n /// @dev address is used but the value corresponds to a AssetId\n function symbol(uint256 assetId) external view returns (string memory);\n}\n\ninterface IERC6909Fungible is IERC6909 {\n /// @notice Mint new tokens for a specific tokenid and assign them to an owner\n ///\n /// @param owner Creates supply of a given `tokenId` by `amount` for owner.\n /// @param tokenId Id of the item\n /// @param amount Adds `amount` to the total supply of the given `tokenId`\n function mint(address owner, uint256 tokenId, uint256 amount) external;\n\n /// @notice Destroy supply of a given tokenId by amount.\n /// @dev The msg.sender MUST be the owner.\n ///\n /// @param owner Owner of the `tokenId`\n /// @param tokenId Id of the item.\n /// @param amount Subtract `amount` from the total supply of the given `tokenId`\n function burn(address owner, uint256 tokenId, uint256 amount) external;\n\n /// @notice Enforces a transfer from `spender` point of view.\n ///\n ///\n /// @param sender The owner of the `tokenId`\n /// @param receiver Address of the receiving party\n /// @param tokenId Token Id\n /// @param amount Amount to be transferred\n function authTransferFrom(address sender, address receiver, uint256 tokenId, uint256 amount)\n external\n returns (bool);\n}\n\n/// @dev A factory contract to deploy new collateral contracts implementing IERC6909.\ninterface IERC6909Factory {\n /// Events\n event NewTokenDeployment(address indexed owner, address instance);\n\n /// @notice Deploys new install of a contract that implements IERC6909.\n /// @dev Factory should deploy deterministically if possible.\n ///\n /// @param owner Owner of the deployed collateral contract which has initial full rights.\n /// @param salt Used to make a deterministic deployment.\n /// @return An address of the newly deployed contract.\n function deploy(address owner, bytes32 salt) external returns (address);\n\n /// @notice Generates a new deterministic address based on the owner and the salt.\n ///\n /// @param owner Owner of the deployed collateral contract which has initial full rights.\n /// @param salt Used to make a deterministic deployment.\n /// @return An address of the newly deployed contract.\n function previewAddress(address owner, bytes32 salt) external returns (address);\n}\n" + }, + "src/misc/interfaces/IERC7540.sol": { + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.5.0;\n\nimport {IRecoverable} from \"src/misc/interfaces/IRecoverable.sol\";\nimport {IERC7575, IERC165} from \"src/misc/interfaces/IERC7575.sol\";\n\ninterface IERC7540Operator {\n /**\n * @dev The event emitted when an operator is set.\n *\n * @param controller The address of the controller.\n * @param operator The address of the operator.\n * @param approved The approval status.\n */\n event OperatorSet(address indexed controller, address indexed operator, bool approved);\n\n /**\n * @dev Sets or removes an operator for the caller.\n *\n * @param operator The address of the operator.\n * @param approved The approval status.\n * @return Whether the call was executed successfully or not\n */\n function setOperator(address operator, bool approved) external returns (bool);\n\n /**\n * @dev Returns `true` if the `operator` is approved as an operator for an `controller`.\n *\n * @param controller The address of the controller.\n * @param operator The address of the operator.\n * @return status The approval status\n */\n function isOperator(address controller, address operator) external view returns (bool status);\n}\n\ninterface IERC7540Deposit is IERC7540Operator {\n event DepositRequest(\n address indexed controller, address indexed owner, uint256 indexed requestId, address sender, uint256 assets\n );\n /**\n * @dev Transfers assets from sender into the Vault and submits a Request for asynchronous deposit.\n *\n * - MUST support ERC-20 approve / transferFrom on asset as a deposit Request flow.\n * - MUST revert if all of assets cannot be requested for deposit.\n * - owner MUST be msg.sender unless some unspecified explicit approval is given by the caller,\n * approval of ERC-20 tokens from owner to sender is NOT enough.\n *\n * @param assets the amount of deposit assets to transfer from owner\n * @param controller the controller of the request who will be able to operate the request\n * @param owner the source of the deposit assets\n *\n * NOTE: most implementations will require pre-approval of the Vault with the Vault's underlying asset token.\n */\n\n function requestDeposit(uint256 assets, address controller, address owner) external returns (uint256 requestId);\n\n /**\n * @dev Returns the amount of requested assets in Pending state.\n *\n * - MUST NOT include any assets in Claimable state for deposit or mint.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT revert unless due to integer overflow caused by an unreasonably large input.\n */\n function pendingDepositRequest(uint256 requestId, address controller)\n external\n view\n returns (uint256 pendingAssets);\n\n /**\n * @dev Returns the amount of requested assets in Claimable state for the controller to deposit or mint.\n *\n * - MUST NOT include any assets in Pending state.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT revert unless due to integer overflow caused by an unreasonably large input.\n */\n function claimableDepositRequest(uint256 requestId, address controller)\n external\n view\n returns (uint256 claimableAssets);\n\n /**\n * @dev Mints shares Vault shares to receiver by claiming the Request of the controller.\n *\n * - MUST emit the Deposit event.\n * - controller MUST equal msg.sender unless the controller has approved the msg.sender as an operator.\n */\n function deposit(uint256 assets, address receiver, address controller) external returns (uint256 shares);\n\n /**\n * @dev Mints exactly shares Vault shares to receiver by claiming the Request of the controller.\n *\n * - MUST emit the Deposit event.\n * - controller MUST equal msg.sender unless the controller has approved the msg.sender as an operator.\n */\n function mint(uint256 shares, address receiver, address controller) external returns (uint256 assets);\n}\n\ninterface IERC7540Redeem is IERC7540Operator {\n event RedeemRequest(\n address indexed controller, address indexed owner, uint256 indexed requestId, address sender, uint256 assets\n );\n\n /**\n * @dev Assumes control of shares from sender into the Vault and submits a Request for asynchronous redeem.\n *\n * - MUST support a redeem Request flow where the control of shares is taken from sender directly\n * where msg.sender has ERC-20 approval over the shares of owner.\n * - MUST revert if all of shares cannot be requested for redeem.\n *\n * @param shares the amount of shares to be redeemed to transfer from owner\n * @param controller the controller of the request who will be able to operate the request\n * @param owner the source of the shares to be redeemed\n *\n * NOTE: most implementations will require pre-approval of the Vault with the Vault's share token.\n */\n function requestRedeem(uint256 shares, address controller, address owner) external returns (uint256 requestId);\n\n /**\n * @dev Returns the amount of requested shares in Pending state.\n *\n * - MUST NOT include any shares in Claimable state for redeem or withdraw.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT revert unless due to integer overflow caused by an unreasonably large input.\n */\n function pendingRedeemRequest(uint256 requestId, address controller)\n external\n view\n returns (uint256 pendingShares);\n\n /**\n * @dev Returns the amount of requested shares in Claimable state for the controller to redeem or withdraw.\n *\n * - MUST NOT include any shares in Pending state for redeem or withdraw.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT revert unless due to integer overflow caused by an unreasonably large input.\n */\n function claimableRedeemRequest(uint256 requestId, address controller)\n external\n view\n returns (uint256 claimableShares);\n}\n\ninterface IERC7887Deposit {\n event CancelDepositRequest(address indexed controller, uint256 indexed requestId, address sender);\n event CancelDepositClaim(\n address indexed controller, address indexed receiver, uint256 indexed requestId, address sender, uint256 assets\n );\n\n /**\n * @dev Submits a Request for cancelling the pending deposit Request\n *\n * - controller MUST be msg.sender unless some unspecified explicit approval is given by the caller,\n * approval of ERC-20 tokens from controller to sender is NOT enough.\n * - MUST set pendingCancelDepositRequest to `true` for the returned requestId after request\n * - MUST increase claimableCancelDepositRequest for the returned requestId after fulfillment\n * - SHOULD be claimable using `claimCancelDepositRequest`\n * Note: while `pendingCancelDepositRequest` is `true`, `requestDeposit` cannot be called\n */\n function cancelDepositRequest(uint256 requestId, address controller) external;\n\n /**\n * @dev Returns whether the deposit Request is pending cancelation\n *\n * - MUST NOT show any variations depending on the caller.\n */\n function pendingCancelDepositRequest(uint256 requestId, address controller)\n external\n view\n returns (bool isPending);\n\n /**\n * @dev Returns the amount of assets that were canceled from a deposit Request, and can now be claimed.\n *\n * - MUST NOT show any variations depending on the caller.\n */\n function claimableCancelDepositRequest(uint256 requestId, address controller)\n external\n view\n returns (uint256 claimableAssets);\n\n /**\n * @dev Claims the canceled deposit assets, and removes the pending cancelation Request\n *\n * - controller MUST be msg.sender unless some unspecified explicit approval is given by the caller,\n * approval of ERC-20 tokens from controller to sender is NOT enough.\n * - MUST set pendingCancelDepositRequest to `false` for the returned requestId after request\n * - MUST set claimableCancelDepositRequest to 0 for the returned requestId after fulfillment\n */\n function claimCancelDepositRequest(uint256 requestId, address receiver, address controller)\n external\n returns (uint256 assets);\n}\n\ninterface IERC7887Redeem {\n event CancelRedeemRequest(address indexed controller, uint256 indexed requestId, address sender);\n event CancelRedeemClaim(\n address indexed controller, address indexed receiver, uint256 indexed requestId, address sender, uint256 shares\n );\n\n /**\n * @dev Submits a Request for cancelling the pending redeem Request\n *\n * - controller MUST be msg.sender unless some unspecified explicit approval is given by the caller,\n * approval of ERC-20 tokens from controller to sender is NOT enough.\n * - MUST set pendingCancelRedeemRequest to `true` for the returned requestId after request\n * - MUST increase claimableCancelRedeemRequest for the returned requestId after fulfillment\n * - SHOULD be claimable using `claimCancelRedeemRequest`\n * Note: while `pendingCancelRedeemRequest` is `true`, `requestRedeem` cannot be called\n */\n function cancelRedeemRequest(uint256 requestId, address controller) external;\n\n /**\n * @dev Returns whether the redeem Request is pending cancelation\n *\n * - MUST NOT show any variations depending on the caller.\n */\n function pendingCancelRedeemRequest(uint256 requestId, address controller) external view returns (bool isPending);\n\n /**\n * @dev Returns the amount of shares that were canceled from a redeem Request, and can now be claimed.\n *\n * - MUST NOT show any variations depending on the caller.\n */\n function claimableCancelRedeemRequest(uint256 requestId, address controller)\n external\n view\n returns (uint256 claimableShares);\n\n /**\n * @dev Claims the canceled redeem shares, and removes the pending cancelation Request\n *\n * - controller MUST be msg.sender unless some unspecified explicit approval is given by the caller,\n * approval of ERC-20 tokens from controller to sender is NOT enough.\n * - MUST set pendingCancelRedeemRequest to `false` for the returned requestId after request\n * - MUST set claimableCancelRedeemRequest to 0 for the returned requestId after fulfillment\n */\n function claimCancelRedeemRequest(uint256 requestId, address receiver, address controller)\n external\n returns (uint256 shares);\n}\n\ninterface IERC7741 {\n /**\n * @dev Grants or revokes permissions for `operator` to manage Requests on behalf of the\n * `msg.sender`, using an [EIP-712](./eip-712.md) signature.\n */\n function authorizeOperator(\n address controller,\n address operator,\n bool approved,\n bytes32 nonce,\n uint256 deadline,\n bytes memory signature\n ) external returns (bool);\n\n /**\n * @dev Revokes the given `nonce` for `msg.sender` as the `owner`.\n */\n function invalidateNonce(bytes32 nonce) external;\n\n /**\n * @dev Returns whether the given `nonce` has been used for the `controller`.\n */\n function authorizations(address controller, bytes32 nonce) external view returns (bool used);\n\n /**\n * @dev Returns the `DOMAIN_SEPARATOR` as defined according to EIP-712. The `DOMAIN_SEPARATOR\n * should be unique to the contract and chain to prevent replay attacks from other domains,\n * and satisfy the requirements of EIP-712, but is otherwise unconstrained.\n */\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\ninterface IERC7714 {\n /**\n * @dev Returns `true` if the `user` is permissioned to interact with the contract.\n */\n function isPermissioned(address controller) external view returns (bool);\n}\n" + }, + "src/misc/interfaces/IERC7575.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\ninterface IERC7575 is IERC165 {\n event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares);\n event Withdraw(\n address indexed sender, address indexed receiver, address indexed owner, uint256 assets, uint256 shares\n );\n\n /**\n * @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.\n *\n * - MUST be an ERC-20 token contract.\n * - MUST NOT revert.\n */\n function asset() external view returns (address assetTokenAddress);\n\n /**\n * @dev Returns the address of the share token\n *\n * - MUST be an ERC-20 token contract.\n * - MUST NOT revert.\n */\n function share() external view returns (address shareTokenAddress);\n\n /**\n * @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal\n * scenario where all the conditions are met.\n *\n * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.\n * - MUST NOT revert.\n *\n * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the\n * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and\n * from.\n */\n function convertToShares(uint256 assets) external view returns (uint256 shares);\n\n /**\n * @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal\n * scenario where all the conditions are met.\n *\n * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.\n * - MUST NOT revert.\n *\n * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the\n * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and\n * from.\n */\n function convertToAssets(uint256 shares) external view returns (uint256 assets);\n\n /**\n * @dev Returns the total amount of the underlying asset that is “managed” by Vault.\n *\n * - SHOULD include any compounding that occurs from yield.\n * - MUST be inclusive of any fees that are charged against assets in the Vault.\n * - MUST NOT revert.\n */\n function totalAssets() external view returns (uint256 totalManagedAssets);\n\n /**\n * @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,\n * through a deposit call.\n *\n * - MUST return a limited value if receiver is subject to some deposit limit.\n * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.\n * - MUST NOT revert.\n */\n function maxDeposit(address receiver) external view returns (uint256 maxAssets);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given\n * current on-chain conditions.\n *\n * - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit\n * call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called\n * in the same transaction.\n * - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the\n * deposit would be accepted, regardless if the user has enough tokens approved, etc.\n * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by depositing.\n */\n function previewDeposit(uint256 assets) external view returns (uint256 shares);\n\n /**\n * @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens.\n *\n * - MUST emit the Deposit event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n * deposit execution, and are accounted for during deposit.\n * - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not\n * approving enough underlying tokens to the Vault contract, etc).\n *\n * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.\n */\n function deposit(uint256 assets, address receiver) external returns (uint256 shares);\n\n /**\n * @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.\n * - MUST return a limited value if receiver is subject to some mint limit.\n * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.\n * - MUST NOT revert.\n */\n function maxMint(address receiver) external view returns (uint256 maxShares);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given\n * current on-chain conditions.\n *\n * - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call\n * in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the\n * same transaction.\n * - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint\n * would be accepted, regardless if the user has enough tokens approved, etc.\n * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by minting.\n */\n function previewMint(uint256 shares) external view returns (uint256 assets);\n\n /**\n * @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.\n *\n * - MUST emit the Deposit event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint\n * execution, and are accounted for during mint.\n * - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not\n * approving enough underlying tokens to the Vault contract, etc).\n *\n * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.\n */\n function mint(uint256 shares, address receiver) external returns (uint256 assets);\n\n /**\n * @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the\n * Vault, through a withdraw call.\n *\n * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.\n * - MUST NOT revert.\n */\n function maxWithdraw(address owner) external view returns (uint256 maxAssets);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,\n * given current on-chain conditions.\n *\n * - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw\n * call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if\n * called\n * in the same transaction.\n * - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though\n * the withdrawal would be accepted, regardless if the user has enough shares, etc.\n * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by depositing.\n */\n function previewWithdraw(uint256 assets) external view returns (uint256 shares);\n\n /**\n * @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver.\n *\n * - MUST emit the Withdraw event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n * withdraw execution, and are accounted for during withdraw.\n * - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner\n * not having enough shares, etc).\n *\n * Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.\n * Those methods should be performed separately.\n */\n function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares);\n\n /**\n * @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault,\n * through a redeem call.\n *\n * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.\n * - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock.\n * - MUST NOT revert.\n */\n function maxRedeem(address owner) external view returns (uint256 maxShares);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block,\n * given current on-chain conditions.\n *\n * - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call\n * in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the\n * same transaction.\n * - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the\n * redemption would be accepted, regardless if the user has enough shares, etc.\n * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by redeeming.\n */\n function previewRedeem(uint256 shares) external view returns (uint256 assets);\n\n /**\n * @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver.\n *\n * - MUST emit the Withdraw event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n * redeem execution, and are accounted for during redeem.\n * - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner\n * not having enough shares, etc).\n *\n * NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed.\n * Those methods should be performed separately.\n */\n function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets);\n}\n\ninterface IERC7575Share is IERC165 {\n event VaultUpdate(address indexed asset, address vault);\n\n /**\n * @dev Returns the address of the Vault for the given asset.\n *\n * @param asset the ERC-20 token to deposit with into the Vault\n */\n function vault(address asset) external view returns (address);\n}\n" + }, + "src/misc/interfaces/IERC7726.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\n/// [ERC-7726](https://eips.ethereum.org/EIPS/eip-7726): Common Quote Oracle\n/// Interface for asset conversions.\ninterface IERC7726 {\n /// @notice Returns the value of baseAmount of base in quote terms, e.g. 10 ETH (base) in USDC (quote).\n /// @param base The asset in which the baseAmount is denominated in\n /// @param quote The asset in which the user needs to value the baseAmount\n /// @param baseAmount The amount of base in base terms.\n function getQuote(uint256 baseAmount, address base, address quote) external view returns (uint256 quoteAmount);\n}\n" + }, + "src/misc/interfaces/IIdentityValuation.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IERC7726} from \"src/misc/interfaces/IERC7726.sol\";\n\n/// @notice An IERC7726 valuation that always values 1:1.\ninterface IIdentityValuation is IERC7726 {}\n" + }, + "src/misc/interfaces/IMulticall.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\n/// @notice Allows to call several calls of the same contract in a single transaction\ninterface IMulticall {\n /// @notice Dispatched when an empty revert is dispatched in a method in the multicall\n error CallFailedWithEmptyRevert();\n\n /// @notice Allows caller to execute multiple (batched) messages calls in one transaction.\n /// @param data An array of encoded methods of the same contract.\n /// @dev No reentrant execution is allowed.\n /// If one call fails, it reverts the whole transaction.\n /// In order to provide the correct value for functions that require top up,\n /// the caller must estimate separately, in advance, how much each of the message call will cost.\n /// The `msg.value` when calling this method must be the sum of all estimates.\n function multicall(bytes[] calldata data) external payable;\n}\n" + }, + "src/misc/interfaces/IRecoverable.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\naddress constant ETH_ADDRESS = address(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);\n\ninterface IRecoverable {\n /// @notice Used to recover any ERC-20 token.\n /// @dev This method is called only by authorized entities\n /// @param token It could be 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee\n /// to recover locked native ETH or token compatible with ERC20.\n /// @param to Receiver of the funds\n /// @param amount Amount to send to the receiver.\n function recoverTokens(address token, address to, uint256 amount) external;\n\n /// @notice Used to recover any ERC-20 or ERC-6909 token.\n /// @dev This method is called only by authorized entities\n /// @param token It could be 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee\n /// to recover locked native ETH or token compatible with ERC20 or ERC6909.\n /// @param tokenId The token id, i.e. non-zero if the underlying token is ERC6909 and else zero.\n /// @param to Receiver of the funds\n /// @param amount Amount to send to the receiver.\n function recoverTokens(address token, uint256 tokenId, address to, uint256 amount) external;\n}\n" + }, + "src/misc/libraries/ArrayLib.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\n/// @title ArrayLib\nlibrary ArrayLib {\n error InvalidValues();\n\n function countNonZeroValues(uint16[8] memory arr) internal pure returns (uint8 count) {\n uint256 elementsCount = arr.length;\n for (uint256 i; i < elementsCount; i++) {\n if (arr[i] != 0) ++count;\n }\n }\n\n function decreaseFirstNValues(uint16[8] storage arr, uint8 numValues) internal {\n uint256 elementsCount = arr.length;\n for (uint256 i; i < elementsCount; i++) {\n if (numValues == 0) return;\n\n if (arr[i] != 0) {\n arr[i] -= 1;\n numValues--;\n }\n }\n\n require(numValues == 0, InvalidValues());\n }\n\n function isEmpty(uint16[8] memory arr) internal pure returns (bool) {\n uint256 elementsCount = arr.length;\n for (uint256 i; i < elementsCount; i++) {\n if (arr[i] != 0) return false;\n }\n return true;\n }\n}\n" + }, + "src/misc/libraries/BitmapLib.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\n/// @title BitmapLib\nlibrary BitmapLib {\n function setBit(uint128 bitmap, uint128 index, bool isTrue) internal pure returns (uint128) {\n if (isTrue) {\n return bitmap | (uint128(1) << index);\n }\n\n return bitmap & ~(uint128(1) << index);\n }\n\n function getBit(uint128 bitmap, uint128 index) internal pure returns (bool) {\n uint128 bitAtIndex = uint128(bitmap & (1 << index));\n return bitAtIndex != 0;\n }\n}\n" + }, + "src/misc/libraries/BytesLib.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\n/// @title Bytes Lib\n/// @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity.\n/// The library lets you concatenate, slice and type cast bytes arrays both in memory and storage.\n/// @author Modified from Solidity Bytes Arrays Utils v0.8.0\nlibrary BytesLib {\n error SliceOverflow();\n error SliceOutOfBounds();\n\n function sliceZeroPadded(bytes memory _bytes, uint256 _start, uint256 _length)\n internal\n pure\n returns (bytes memory)\n {\n require(_length + 31 >= _length, SliceOverflow());\n\n bytes memory tempBytes;\n\n assembly {\n switch iszero(_length)\n case 0 {\n // Get a location of some free memory and store it in tempBytes as\n // Solidity does for memory variables.\n tempBytes := mload(0x40)\n\n // The first word of the slice result is potentially a partial\n // word read from the original array. To read it, we calculate\n // the length of that partial word and start copying that many\n // bytes into the array. The first word we copy will start with\n // data we don't care about, but the last `lengthmod` bytes will\n // land at the beginning of the contents of the new array. When\n // we're done copying, we overwrite the full first word with\n // the actual length of the slice.\n let lengthmod := and(_length, 31)\n\n // The multiplication in the next line is necessary\n // because when slicing multiples of 32 bytes (lengthmod == 0)\n // the following copy loop was copying the origin's length\n // and then ending prematurely not copying everything it should.\n let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))\n let end := add(mc, _length)\n\n for {\n // The multiplication in the next line has the same exact purpose\n // as the one above.\n let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)\n } lt(mc, end) {\n mc := add(mc, 0x20)\n cc := add(cc, 0x20)\n } { mstore(mc, mload(cc)) }\n\n mstore(tempBytes, _length)\n\n //update free-memory pointer\n //allocating the array padded to 32 bytes like the compiler does now\n mstore(0x40, and(add(mc, 31), not(31)))\n }\n //if we want a zero-length slice let's just return a zero-length array\n default {\n tempBytes := mload(0x40)\n //zero out the 32 bytes slice we are about to return\n //we need to do it because Solidity does not garbage collect\n mstore(tempBytes, 0)\n\n mstore(0x40, add(tempBytes, 0x20))\n }\n }\n\n return tempBytes;\n }\n\n function slice(bytes memory _bytes, uint256 _start, uint256 _length) internal pure returns (bytes memory) {\n require(_bytes.length >= _start + _length, SliceOutOfBounds());\n return sliceZeroPadded(_bytes, _start, _length);\n }\n\n function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) {\n require(_bytes.length >= _start + 20, SliceOutOfBounds());\n address tempAddress;\n\n assembly {\n tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000)\n }\n\n return tempAddress;\n }\n\n function toUint8(bytes memory _bytes, uint256 _start) internal pure returns (uint8) {\n require(_bytes.length >= _start + 1, SliceOutOfBounds());\n uint8 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x1), _start))\n }\n\n return tempUint;\n }\n\n function toUint16(bytes memory _bytes, uint256 _start) internal pure returns (uint16) {\n require(_bytes.length >= _start + 2, SliceOutOfBounds());\n uint16 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x2), _start))\n }\n\n return tempUint;\n }\n\n function toUint32(bytes memory _bytes, uint256 _start) internal pure returns (uint32) {\n require(_bytes.length >= _start + 4, SliceOutOfBounds());\n uint32 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x4), _start))\n }\n\n return tempUint;\n }\n\n function toUint64(bytes memory _bytes, uint256 _start) internal pure returns (uint64) {\n require(_bytes.length >= _start + 8, SliceOutOfBounds());\n uint64 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x8), _start))\n }\n\n return tempUint;\n }\n\n function toUint128(bytes memory _bytes, uint256 _start) internal pure returns (uint128) {\n require(_bytes.length >= _start + 16, SliceOutOfBounds());\n uint128 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x10), _start))\n }\n\n return tempUint;\n }\n\n function toUint256(bytes memory _bytes, uint256 _start) internal pure returns (uint256) {\n require(_bytes.length >= _start + 32, SliceOutOfBounds());\n uint256 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x20), _start))\n }\n\n return tempUint;\n }\n\n function toBytes32(bytes memory _bytes, uint256 _start) internal pure returns (bytes32) {\n require(_bytes.length >= _start + 32, SliceOutOfBounds());\n bytes32 tempBytes32;\n\n assembly {\n tempBytes32 := mload(add(add(_bytes, 0x20), _start))\n }\n\n return tempBytes32;\n }\n\n function toBytes16(bytes memory _bytes, uint256 _start) internal pure returns (bytes16) {\n require(_bytes.length >= _start + 16, SliceOutOfBounds());\n bytes16 tempBytes16;\n\n assembly {\n tempBytes16 := mload(add(add(_bytes, 0x20), _start))\n }\n\n return tempBytes16;\n }\n\n function toBool(bytes memory _bytes, uint256 _start) internal pure returns (bool) {\n require(_bytes.length > _start, SliceOutOfBounds());\n return _bytes[_start] != 0;\n }\n}\n" + }, + "src/misc/libraries/CastLib.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\n/// @title CastLib\nlibrary CastLib {\n function toAddressLeftPadded(bytes32 addr) internal pure returns (address) {\n require(bytes12(addr) == 0, \"First 12 bytes should be zero\");\n return address(uint160(uint256(addr)));\n }\n\n function toBytes32LeftPadded(address addr) internal pure returns (bytes32) {\n return bytes32(uint256(uint160(addr)));\n }\n\n function toAddress(bytes32 addr) internal pure returns (address) {\n require(uint96(uint256(addr)) == 0, \"Input should be 20 bytes\");\n return address(bytes20(addr));\n }\n\n function toString(address addr) internal pure returns (string memory) {\n return string(abi.encodePacked(addr));\n }\n\n function toBytes32(address addr) internal pure returns (bytes32) {\n return bytes32(bytes20(addr));\n }\n\n /// @dev Adds zero padding\n function toBytes32(string memory source) internal pure returns (bytes32) {\n return bytes32(bytes(source));\n }\n\n /// @dev Removes zero padding\n function bytes128ToString(bytes memory _bytes128) internal pure returns (string memory) {\n require(_bytes128.length == 128, \"Input should be 128 bytes\");\n\n uint8 i = 0;\n while (i < 128 && _bytes128[i] != 0) {\n i++;\n }\n\n bytes memory bytesArray = new bytes(i);\n\n for (uint8 j; j < i; j++) {\n bytesArray[j] = _bytes128[j];\n }\n\n return string(bytesArray);\n }\n\n function toString(bytes32 _bytes32) internal pure returns (string memory) {\n uint8 i = 0;\n while (i < 32 && _bytes32[i] != 0) {\n i++;\n }\n bytes memory bytesArray = new bytes(i);\n for (i = 0; i < 32 && _bytes32[i] != 0; i++) {\n bytesArray[i] = _bytes32[i];\n }\n return string(bytesArray);\n }\n}\n" + }, + "src/misc/libraries/EIP712Lib.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\n/// @title EIP712 Lib\nlibrary EIP712Lib {\n // keccak256(\"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\")\n bytes32 public constant EIP712_DOMAIN_TYPEHASH = 0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f;\n\n function calculateDomainSeparator(bytes32 nameHash, bytes32 versionHash) internal view returns (bytes32) {\n return keccak256(abi.encode(EIP712_DOMAIN_TYPEHASH, nameHash, versionHash, block.chainid, address(this)));\n }\n}\n" + }, + "src/misc/libraries/MathLib.sol": { + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.28;\n\nlibrary MathLib {\n enum Rounding {\n Down, // Toward negative infinity\n Up, // Toward infinity\n Zero // Toward zero\n\n }\n\n error MulDiv_Overflow();\n error Uint8_Overflow();\n error Uint32_Overflow();\n error Uint64_Overflow();\n error Uint128_Overflow();\n error Int128_Overflow();\n\n uint256 public constant One27 = 10 ** 27;\n\n /// @notice Returns x^n with rounding precision of base\n ///\n /// @dev Source: https://github.com/makerdao/dss/blob/fa4f6630afb0624d04a003e920b0d71a00331d98/src/jug.sol#L62\n ///\n /// @param x The base value which should be exponentiated\n /// @param n The exponent\n /// @param base The scaling base, typically used for fix-point calculations\n function rpow(uint256 x, uint256 n, uint256 base) public pure returns (uint256 z) {\n assembly {\n switch x\n case 0 {\n switch n\n case 0 { z := base }\n default { z := 0 }\n }\n default {\n switch mod(n, 2)\n case 0 { z := base }\n default { z := x }\n let half := div(base, 2) // for rounding.\n for { n := div(n, 2) } n { n := div(n, 2) } {\n let xx := mul(x, x)\n if iszero(eq(div(xx, x), x)) { revert(0, 0) }\n let xxRound := add(xx, half)\n if lt(xxRound, xx) { revert(0, 0) }\n x := div(xxRound, base)\n if mod(n, 2) {\n let zx := mul(z, x)\n if and(iszero(iszero(x)), iszero(eq(div(zx, x), z))) { revert(0, 0) }\n let zxRound := add(zx, half)\n if lt(zxRound, zx) { revert(0, 0) }\n z := div(zxRound, base)\n }\n }\n }\n }\n }\n\n /// @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or\n /// denominator == 0\n /// @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\n /// with further edits by Uniswap Labs also under MIT license.\n // slither-disable-start divide-before-multiply\n function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {\n unchecked {\n // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\n // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\n // variables such that product = prod1 * 2^256 + prod0.\n uint256 prod0; // Least significant 256 bits of the product\n uint256 prod1; // Most significant 256 bits of the product\n assembly {\n let mm := mulmod(x, y, not(0))\n prod0 := mul(x, y)\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n }\n\n // Handle non-overflow cases, 256 by 256 division.\n if (prod1 == 0) {\n // Solidity will revert if denominator == 0, unlike the div opcode on its own.\n // The surrounding unchecked block does not change this fact.\n // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.\n return prod0 / denominator;\n }\n\n // Make sure the result is less than 2^256. Also prevents denominator == 0.\n require(denominator > prod1, MulDiv_Overflow());\n\n ///////////////////////////////////////////////\n // 512 by 256 division.\n ///////////////////////////////////////////////\n\n // Make division exact by subtracting the remainder from [prod1 prod0].\n uint256 remainder;\n assembly {\n // Compute remainder using mulmod.\n remainder := mulmod(x, y, denominator)\n\n // Subtract 256 bit number from 512 bit number.\n prod1 := sub(prod1, gt(remainder, prod0))\n prod0 := sub(prod0, remainder)\n }\n\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator.\n // Always >= 1.\n // See https://cs.stackexchange.com/q/138556/92363.\n\n // Does not overflow because the denominator cannot be zero at this stage in the function.\n uint256 twos = denominator & (~denominator + 1);\n assembly {\n // Divide denominator by twos.\n denominator := div(denominator, twos)\n\n // Divide [prod1 prod0] by twos.\n prod0 := div(prod0, twos)\n\n // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\n twos := add(div(sub(0, twos), twos), 1)\n }\n\n // Shift in bits from prod1 into prod0.\n prod0 |= prod1 * twos;\n\n // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\n // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\n // four bits. That is, denominator * inv = 1 mod 2^4.\n uint256 inverse = (3 * denominator) ^ 2;\n\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also\n // works\n // in modular arithmetic, doubling the correct bits in each step.\n inverse *= 2 - denominator * inverse; // inverse mod 2^8\n inverse *= 2 - denominator * inverse; // inverse mod 2^16\n inverse *= 2 - denominator * inverse; // inverse mod 2^32\n inverse *= 2 - denominator * inverse; // inverse mod 2^64\n inverse *= 2 - denominator * inverse; // inverse mod 2^128\n inverse *= 2 - denominator * inverse; // inverse mod 2^256\n\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\n // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\n // is no longer required.\n result = prod0 * inverse;\n return result;\n }\n }\n // slither-disable-end divide-before-multiply\n\n /// @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\n function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {\n uint256 result = mulDiv(x, y, denominator);\n if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\n result += 1;\n }\n return result;\n }\n\n /// @notice Safe type conversion from uint256 to uint8.\n function toUint8(uint256 value) internal pure returns (uint8) {\n require(value <= type(uint8).max, Uint8_Overflow());\n return uint8(value);\n }\n\n function toUint32(uint256 value) internal pure returns (uint32) {\n require(value <= type(uint32).max, Uint32_Overflow());\n return uint32(value);\n }\n\n function toUint64(uint256 value) internal pure returns (uint64) {\n require(value <= type(uint64).max, Uint64_Overflow());\n return uint64(value);\n }\n\n /// @notice Safe type conversion from uint256 to uint128.\n function toUint128(uint256 value) internal pure returns (uint128) {\n require(value <= type(uint128).max, Uint128_Overflow());\n return uint128(value);\n }\n\n /// @notice Returns the smallest of two numbers.\n function min(uint256 a, uint256 b) internal pure returns (uint256) {\n return a > b ? b : a;\n }\n\n /// @notice Returns the largest of two numbers.\n function max(uint256 a, uint256 b) internal pure returns (uint256) {\n return a > b ? a : b;\n }\n}\n" + }, + "src/misc/libraries/SafeTransferLib.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IERC20} from \"src/misc/interfaces/IERC20.sol\";\n\n/// @title Safe Transfer Lib\n/// @author Modified from Uniswap v3 Periphery (libraries/TransferHelper.sol)\nlibrary SafeTransferLib {\n error NoCode();\n error SafeTransferFromFailed();\n error SafeTransferFailed();\n error SafeApproveFailed();\n error SafeTransferEthFailed();\n\n /// @notice Transfers tokens from the targeted address to the given destination\n /// @notice Errors if transfer fails\n /// @param token The contract address of the token to be transferred\n /// @param from The originating address from which the tokens will be transferred\n /// @param to The destination address of the transfer\n /// @param value The amount to be transferred\n function safeTransferFrom(address token, address from, address to, uint256 value) internal {\n require(address(token).code.length > 0, NoCode());\n\n (bool success, bytes memory data) = token.call(abi.encodeCall(IERC20.transferFrom, (from, to, value)));\n require(success && (data.length == 0 || abi.decode(data, (bool))), SafeTransferFromFailed());\n }\n\n /// @notice Transfers tokens from msg.sender to a recipient\n /// @dev Errors if transfer fails\n /// @param token The contract address of the token which will be transferred\n /// @param to The recipient of the transfer\n /// @param value The value of the transfer\n function safeTransfer(address token, address to, uint256 value) internal {\n require(address(token).code.length > 0, NoCode());\n\n (bool success, bytes memory data) = token.call(abi.encodeCall(IERC20.transfer, (to, value)));\n require(success && (data.length == 0 || abi.decode(data, (bool))), SafeTransferFailed());\n }\n\n /// @notice Approves the stipulated contract to spend the given allowance in the given token\n /// @dev Errors if approval fails\n /// @param token The contract address of the token to be approved\n /// @param to The target of the approval\n /// @param value The amount of the given token the target will be allowed to spend\n function safeApprove(address token, address to, uint256 value) internal {\n require(address(token).code.length > 0, NoCode());\n\n (bool success, bytes memory data) = token.call(abi.encodeCall(IERC20.approve, (to, value)));\n require(success && (data.length == 0 || abi.decode(data, (bool))), SafeApproveFailed());\n }\n\n /// @notice Transfers ETH to the recipient address\n /// @dev Fails with `STE`\n /// @dev Make sure that method that is using this function is protected from reentrancy\n /// @param to The destination of the transfer\n /// @param value The value to be transferred\n function safeTransferETH(address to, uint256 value) internal {\n (bool success,) = to.call{value: value}(new bytes(0));\n require(success, SafeTransferEthFailed());\n }\n}\n" + }, + "src/misc/libraries/SignatureLib.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\ninterface IERC1271 {\n function isValidSignature(bytes32, bytes memory) external view returns (bytes4);\n}\n\n/// @title Signature Lib\nlibrary SignatureLib {\n error InvalidSigner();\n\n function isValidSignature(address signer, bytes32 digest, bytes memory signature)\n internal\n view\n returns (bool valid)\n {\n require(signer != address(0), InvalidSigner());\n\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n if (signer == ecrecover(digest, v, r, s)) {\n return true;\n }\n }\n\n if (signer.code.length > 0) {\n (bool success, bytes memory result) =\n signer.staticcall(abi.encodeCall(IERC1271.isValidSignature, (digest, signature)));\n valid =\n (success && result.length == 32 && abi.decode(result, (bytes4)) == IERC1271.isValidSignature.selector);\n }\n }\n}\n" + }, + "src/misc/libraries/StringLib.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nlibrary StringLib {\n function isEmpty(string memory value) internal pure returns (bool) {\n return bytes(value).length == 0;\n }\n}\n" + }, + "src/misc/libraries/TransientArrayLib.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {TransientStorageLib} from \"src/misc/libraries/TransientStorageLib.sol\";\n\n/// @title TransientArrayLib\nlibrary TransientArrayLib {\n using TransientStorageLib for bytes32;\n\n function push(bytes32 key, bytes32 value) internal {\n bytes32 lengthSlot = keccak256(abi.encodePacked(key, type(uint256).max));\n uint256 length_ = lengthSlot.tloadUint256();\n lengthSlot.tstore(length_ + 1);\n\n bytes32 slot = keccak256(abi.encodePacked(key, length_));\n slot.tstore(value);\n }\n\n function getBytes32(bytes32 key) internal view returns (bytes32[] memory) {\n uint256 length_ = length(key);\n\n bytes32[] memory data = new bytes32[](length_);\n for (uint256 i = 0; i < length_; i++) {\n bytes32 slot = keccak256(abi.encodePacked(key, i));\n data[i] = slot.tloadBytes32();\n }\n\n return data;\n }\n\n function length(bytes32 key) internal view returns (uint256) {\n return keccak256(abi.encodePacked(key, type(uint256).max)).tloadUint256();\n }\n\n function clear(bytes32 key) internal {\n bytes32 lengthSlot = keccak256(abi.encodePacked(key, type(uint256).max));\n lengthSlot.tstore(uint256(0));\n }\n}\n" + }, + "src/misc/libraries/TransientBytesLib.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\nimport {TransientStorageLib} from \"src/misc/libraries/TransientStorageLib.sol\";\n\n/// @title TransientBytesLib\nlibrary TransientBytesLib {\n using TransientStorageLib for bytes32;\n using BytesLib for bytes;\n\n function append(bytes32 key, bytes memory value) internal {\n bytes32 lengthSlot = keccak256(abi.encodePacked(key, type(uint256).max));\n uint256 prevLength = lengthSlot.tloadUint256();\n\n uint256 startChunk = prevLength / 32;\n uint256 offset = prevLength % 32;\n\n lengthSlot.tstore(prevLength + value.length);\n\n bytes32 joinSlot = keccak256(abi.encodePacked(key, startChunk));\n bytes memory firstPart = abi.encodePacked(joinSlot.tloadBytes32()).sliceZeroPadded(0, offset);\n bytes memory secondPart = value.sliceZeroPadded(0, 32 - offset);\n joinSlot.tstore(bytes32(bytes.concat(firstPart, secondPart)));\n\n uint256 valueOffset = 32 - offset;\n uint256 chunkIndex = startChunk + 1;\n for (; valueOffset < value.length; chunkIndex++) {\n bytes32 slot = keccak256(abi.encodePacked(key, chunkIndex));\n slot.tstore(bytes32(value.sliceZeroPadded(valueOffset, 32)));\n valueOffset += 32;\n }\n }\n\n function get(bytes32 key) internal view returns (bytes memory) {\n bytes memory data;\n uint256 length = keccak256(abi.encodePacked(key, type(uint256).max)).tloadUint256();\n if (length == 0) return data;\n\n uint256 chunks = length / 32 + 1;\n for (uint256 i = 0; i < chunks; i++) {\n bytes32 slot = keccak256(abi.encodePacked(key, i));\n data = bytes.concat(data, slot.tloadBytes32());\n }\n\n return data.slice(0, length);\n }\n\n function clear(bytes32 key) internal {\n bytes32 lengthSlot = keccak256(abi.encodePacked(key, type(uint256).max));\n lengthSlot.tstore(uint256(0));\n }\n}\n" + }, + "src/misc/libraries/TransientStorageLib.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\n/// @title TransientStorageLib\nlibrary TransientStorageLib {\n function tstore(bytes32 slot, address value) internal {\n assembly (\"memory-safe\") {\n tstore(slot, value)\n }\n }\n\n function tstore(bytes32 slot, uint256 value) internal {\n assembly (\"memory-safe\") {\n tstore(slot, value)\n }\n }\n\n function tstore(bytes32 slot, bytes32 value) internal {\n assembly (\"memory-safe\") {\n tstore(slot, value)\n }\n }\n\n function tstore(bytes32 slot, bool value) internal {\n assembly (\"memory-safe\") {\n tstore(slot, value)\n }\n }\n\n function tloadAddress(bytes32 slot) internal view returns (address value) {\n assembly (\"memory-safe\") {\n value := tload(slot)\n }\n }\n\n function tloadUint128(bytes32 slot) internal view returns (uint128 value) {\n assembly (\"memory-safe\") {\n value := tload(slot)\n }\n }\n\n function tloadUint256(bytes32 slot) internal view returns (uint256 value) {\n assembly (\"memory-safe\") {\n value := tload(slot)\n }\n }\n\n function tloadBytes32(bytes32 slot) internal view returns (bytes32 value) {\n assembly (\"memory-safe\") {\n value := tload(slot)\n }\n }\n\n function tloadBool(bytes32 slot) internal view returns (bool value) {\n assembly (\"memory-safe\") {\n value := tload(slot)\n }\n }\n}\n" + }, + "src/misc/types/D18.sol": { + "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.28;\n\n// Small library to handle fixed point number operations with 18 decimals with static typing support.\n\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\n\ntype D18 is uint128;\n\nusing MathLib for uint256;\n\n/// @dev add two D18 types\nfunction add(D18 d1, D18 d2) pure returns (D18) {\n return D18.wrap(D18.unwrap(d1) + D18.unwrap(d2));\n}\n\n/// @dev substract two D18 types\nfunction sub(D18 d1, D18 d2) pure returns (D18) {\n return D18.wrap(D18.unwrap(d1) - D18.unwrap(d2));\n}\n\n/// @dev Divides one D18 by another one while retaining precision:\n/// - nominator (decimal): 50e18\n/// - denominator (decimal): 2e19\n/// - result (decimal): 25e17\nfunction divD18(D18 d1, D18 d2) pure returns (D18) {\n return D18.wrap(MathLib.mulDiv(D18.unwrap(d1), 1e18, D18.unwrap(d2)).toUint128());\n}\n\n/// @dev Multiplies one D18 with another one while retaining precision:\n/// - value1 (decimal): 50e18\n/// - value2 (decimal): 2e19\n/// - result (decimal): 100e19\nfunction mulD18(D18 d1, D18 d2) pure returns (D18) {\n return D18.wrap(MathLib.mulDiv(D18.unwrap(d1), D18.unwrap(d2), 1e18).toUint128());\n}\n\n/// @dev sugar for getting the inner representation of a D18\nfunction inner(D18 d1) pure returns (uint128) {\n return D18.unwrap(d1);\n}\n\n/// @dev Returns the reciprocal of a D18 decimal, i.e. 1 / d.\n/// Example: if d = 2.0 (2e18 internally), reciprocal(d) = 0.5 (5e17 internally).\nfunction reciprocal(D18 d) pure returns (D18) {\n uint128 val = D18.unwrap(d);\n require(val != 0, \"D18/division-by-zero\");\n return d18(1e18, val);\n}\n\n/// @dev Multiplies a decimal by an integer. i.e:\n/// - d (decimal): 1_500_000_000_000_000_000\n/// - value (integer): 4_000_000_000_000_000_000\n/// - result (integer): 6_000_000_000_000_000_000\nfunction mulUint128(D18 d, uint128 value, MathLib.Rounding rounding) pure returns (uint128) {\n return MathLib.mulDiv(D18.unwrap(d), value, 1e18, rounding).toUint128();\n}\n\n/// @dev Multiplies a decimal by an integer. i.e:\n/// - d (decimal): 1_500_000_000_000_000_000\n/// - value (integer): 4_000_000_000_000_000_000\n/// - result (integer): 6_000_000_000_000_000_000\nfunction mulUint256(D18 d, uint256 value, MathLib.Rounding rounding) pure returns (uint256) {\n return MathLib.mulDiv(D18.unwrap(d), value, 1e18, rounding);\n}\n\n/// @dev Divides an integer by a decimal, i.e.\n/// @dev Same as mulDiv for integers, i.e:\n/// - d (decimal): 2_000_000_000_000_000_000\n/// - value (integer): 100_000_000_000_000_000_000\n/// - result (integer): 50_000_000_000_000_000_000\nfunction reciprocalMulUint128(D18 d, uint128 value, MathLib.Rounding rounding) pure returns (uint128) {\n return MathLib.mulDiv(value, 1e18, d.inner(), rounding).toUint128();\n}\n\n/// @dev Divides an integer by a decimal, i.e.\n/// @dev Same as mulDiv for integers, i.e:\n/// - d (decimal): 2_000_000_000_000_000_000\n/// - value (integer): 100_000_000_000_000_000_000\n/// - result (integer): 50_000_000_000_000_000_000\nfunction reciprocalMulUint256(D18 d, uint256 value, MathLib.Rounding rounding) pure returns (uint256) {\n return MathLib.mulDiv(value, 1e18, d.inner(), rounding);\n}\n\n/// @dev Easy way to construct a decimal number\nfunction d18(uint128 value) pure returns (D18) {\n return D18.wrap(value);\n}\n\n/// @dev Easy way to construct a decimal number\nfunction d18(uint128 num, uint128 den) pure returns (D18) {\n return D18.wrap(MathLib.mulDiv(num, 1e18, den).toUint128());\n}\n\nfunction eq(D18 a, D18 b) pure returns (bool) {\n return D18.unwrap(a) == D18.unwrap(b);\n}\n\nfunction raw(D18 d) pure returns (uint128) {\n return D18.unwrap(d);\n}\n\nusing {\n add as +,\n sub as -,\n divD18 as /,\n inner,\n eq,\n mulD18 as *,\n mulUint128,\n mulUint256,\n reciprocalMulUint128,\n reciprocalMulUint256,\n reciprocal,\n raw\n} for D18 global;\n" + }, + "src/vaults/AsyncRequestManager.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\nimport {D18, d18} from \"src/misc/types/D18.sol\";\n\nimport {MessageLib} from \"src/common/libraries/MessageLib.sol\";\nimport {IVaultMessageSender} from \"src/common/interfaces/IGatewaySenders.sol\";\nimport {IRequestManagerGatewayHandler} from \"src/common/interfaces/IGatewayHandlers.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {PricingLib} from \"src/common/libraries/PricingLib.sol\";\n\nimport {IPoolManager, VaultDetails} from \"src/vaults/interfaces/IPoolManager.sol\";\nimport {IBalanceSheet} from \"src/vaults/interfaces/IBalanceSheet.sol\";\nimport {IAsyncRequestManager, AsyncInvestmentState} from \"src/vaults/interfaces/investments/IAsyncRequestManager.sol\";\nimport {IAsyncRedeemManager} from \"src/vaults/interfaces/investments/IAsyncRedeemManager.sol\";\nimport {IAsyncDepositManager} from \"src/vaults/interfaces/investments/IAsyncDepositManager.sol\";\nimport {IDepositManager} from \"src/vaults/interfaces/investments/IDepositManager.sol\";\nimport {IRedeemManager} from \"src/vaults/interfaces/investments/IRedeemManager.sol\";\nimport {IBaseRequestManager} from \"src/vaults/interfaces/investments/IBaseRequestManager.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\nimport {IAsyncVault, IBaseVault, IAsyncRedeemVault, VaultKind} from \"src/vaults/interfaces/IBaseVaults.sol\";\nimport {BaseRequestManager} from \"src/vaults/BaseRequestManager.sol\";\nimport {IPoolEscrowProvider} from \"src/vaults/interfaces/factories/IPoolEscrowFactory.sol\";\nimport {IEscrow} from \"src/vaults/interfaces/IEscrow.sol\";\nimport {ESCROW_HOOK_ID} from \"src/common/interfaces/IHook.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\n\n/// @title Investment Manager\n/// @notice This is the main contract vaults interact with for\n/// both incoming and outgoing investment transactions.\ncontract AsyncRequestManager is BaseRequestManager, IAsyncRequestManager {\n using CastLib for *;\n using MessageLib for *;\n using BytesLib for bytes;\n using MathLib for uint256;\n\n IVaultMessageSender public sender;\n IBalanceSheet public balanceSheet;\n\n mapping(IBaseVault vault => mapping(address investor => AsyncInvestmentState)) public investments;\n\n constructor(IEscrow globalEscrow_, address root_, address deployer)\n BaseRequestManager(globalEscrow_, root_, deployer)\n {}\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n function file(bytes32 what, address data) external override(IBaseRequestManager, BaseRequestManager) auth {\n if (what == \"sender\") sender = IVaultMessageSender(data);\n else if (what == \"poolManager\") poolManager = IPoolManager(data);\n else if (what == \"balanceSheet\") balanceSheet = IBalanceSheet(data);\n else if (what == \"poolEscrowProvider\") poolEscrowProvider = IPoolEscrowProvider(data);\n else revert FileUnrecognizedParam();\n emit File(what, data);\n }\n\n //----------------------------------------------------------------------------------------------\n // Async investment handlers\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IAsyncDepositManager\n function requestDeposit(IBaseVault vault_, uint256 assets, address controller, address, address)\n public\n auth\n returns (bool)\n {\n uint128 assets_ = assets.toUint128();\n require(assets_ != 0, ZeroAmountNotAllowed());\n\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n PoolId poolId = vault_.poolId();\n ShareClassId scId = vault_.scId();\n\n require(poolManager.isLinked(poolId, scId, vaultDetails.asset, vault_), AssetNotAllowed());\n\n require(_canTransfer(vault_, address(0), controller, convertToShares(vault_, assets_)), TransferNotAllowed());\n\n AsyncInvestmentState storage state = investments[vault_][controller];\n require(state.pendingCancelDepositRequest != true, CancellationIsPending());\n\n state.pendingDepositRequest += assets_;\n sender.sendDepositRequest(poolId, scId, controller.toBytes32(), vaultDetails.assetId, assets_);\n\n return true;\n }\n\n /// @inheritdoc IAsyncRedeemManager\n function requestRedeem(IBaseVault vault_, uint256 shares, address controller, address owner, address)\n public\n auth\n returns (bool)\n {\n uint128 shares_ = shares.toUint128();\n require(shares_ != 0, ZeroAmountNotAllowed());\n\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n PoolId poolId = vault_.poolId();\n ShareClassId scId = vault_.scId();\n\n require(poolManager.isLinked(poolId, scId, vaultDetails.asset, vault_), AssetNotAllowed());\n\n require(\n _canTransfer(vault_, owner, ESCROW_HOOK_ID, shares)\n && _canTransfer(vault_, controller, ESCROW_HOOK_ID, shares),\n TransferNotAllowed()\n );\n\n AsyncInvestmentState storage state = investments[vault_][controller];\n require(state.pendingCancelRedeemRequest != true, CancellationIsPending());\n\n state.pendingRedeemRequest = state.pendingRedeemRequest + shares_;\n sender.sendRedeemRequest(poolId, scId, controller.toBytes32(), vaultDetails.assetId, shares_);\n\n return true;\n }\n\n /// @inheritdoc IAsyncDepositManager\n function cancelDepositRequest(IBaseVault vault_, address controller, address) public auth {\n AsyncInvestmentState storage state = investments[vault_][controller];\n require(state.pendingDepositRequest > 0, NoPendingRequest());\n require(state.pendingCancelDepositRequest != true, CancellationIsPending());\n state.pendingCancelDepositRequest = true;\n\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n\n sender.sendCancelDepositRequest(vault_.poolId(), vault_.scId(), controller.toBytes32(), vaultDetails.assetId);\n }\n\n /// @inheritdoc IAsyncRedeemManager\n function cancelRedeemRequest(IBaseVault vault_, address controller, address) public auth {\n uint256 approximateSharesPayout = pendingRedeemRequest(vault_, controller);\n require(approximateSharesPayout > 0, NoPendingRequest());\n require(_canTransfer(vault_, address(0), controller, approximateSharesPayout), TransferNotAllowed());\n\n AsyncInvestmentState storage state = investments[vault_][controller];\n require(state.pendingCancelRedeemRequest != true, CancellationIsPending());\n state.pendingCancelRedeemRequest = true;\n\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n\n sender.sendCancelRedeemRequest(vault_.poolId(), vault_.scId(), controller.toBytes32(), vaultDetails.assetId);\n }\n\n //----------------------------------------------------------------------------------------------\n // Gateway handlers\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IRequestManagerGatewayHandler\n function approvedDeposits(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n uint128 assetAmount,\n D18 pricePoolPerAsset\n ) external auth {\n (address asset, uint256 tokenId) = poolManager.idToAsset(assetId);\n\n // Note deposit and transfer from global escrow into the pool escrow,\n // to make assets available for managers of the balance sheet\n balanceSheet.overridePricePoolPerAsset(poolId, scId, assetId, pricePoolPerAsset);\n balanceSheet.noteDeposit(poolId, scId, asset, tokenId, address(globalEscrow), assetAmount);\n\n address poolEscrow = address(poolEscrowProvider.escrow(poolId));\n globalEscrow.authTransferTo(asset, tokenId, poolEscrow, assetAmount);\n }\n\n /// @inheritdoc IRequestManagerGatewayHandler\n function issuedShares(PoolId poolId, ShareClassId scId, uint128 shareAmount, D18 pricePoolPerShare) external auth {\n balanceSheet.overridePricePoolPerShare(poolId, scId, pricePoolPerShare);\n balanceSheet.issue(poolId, scId, address(globalEscrow), shareAmount);\n }\n\n /// @inheritdoc IRequestManagerGatewayHandler\n function revokedShares(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n uint128 assetAmount,\n uint128 shareAmount,\n D18 pricePoolPerShare\n ) external auth {\n // Lock assets to ensure they are not withdrawn and are available for the redeeming user\n (address asset, uint256 tokenId) = poolManager.idToAsset(assetId);\n poolEscrowProvider.escrow(poolId).reserveIncrease(scId, asset, tokenId, assetAmount);\n\n balanceSheet.overridePricePoolPerShare(poolId, scId, pricePoolPerShare);\n balanceSheet.revoke(poolId, scId, address(globalEscrow), shareAmount);\n }\n\n /// @inheritdoc IRequestManagerGatewayHandler\n function fulfillDepositRequest(\n PoolId poolId,\n ShareClassId scId,\n address user,\n AssetId assetId,\n uint128 assets,\n uint128 shares\n ) public auth {\n IAsyncVault vault_ = IAsyncVault(address(vault[poolId][scId][assetId]));\n\n AsyncInvestmentState storage state = investments[vault_][user];\n require(state.pendingDepositRequest != 0, NoPendingRequest());\n state.depositPrice = _calculatePriceAssetPerShare(\n vault_, state.maxMint + shares, _maxDeposit(vault_, user) + assets, MathLib.Rounding.Down\n );\n state.maxMint = state.maxMint + shares;\n state.pendingDepositRequest = state.pendingDepositRequest > assets ? state.pendingDepositRequest - assets : 0;\n\n if (state.pendingDepositRequest == 0) delete state.pendingCancelDepositRequest;\n\n vault_.onDepositClaimable(user, assets, shares);\n }\n\n /// @inheritdoc IRequestManagerGatewayHandler\n function fulfillRedeemRequest(\n PoolId poolId,\n ShareClassId scId,\n address user,\n AssetId assetId,\n uint128 assets,\n uint128 shares\n ) public auth {\n IAsyncRedeemVault vault_ = IAsyncRedeemVault(address(vault[poolId][scId][assetId]));\n\n AsyncInvestmentState storage state = investments[vault_][user];\n require(state.pendingRedeemRequest != 0, NoPendingRequest());\n\n // Calculate new weighted average redeem price and update order book values\n state.redeemPrice = _calculatePriceAssetPerShare(\n vault_, ((maxRedeem(vault_, user)) + shares).toUint128(), state.maxWithdraw + assets, MathLib.Rounding.Down\n );\n state.maxWithdraw = state.maxWithdraw + assets;\n state.pendingRedeemRequest = state.pendingRedeemRequest > shares ? state.pendingRedeemRequest - shares : 0;\n\n if (state.pendingRedeemRequest == 0) delete state.pendingCancelRedeemRequest;\n\n vault_.onRedeemClaimable(user, assets, shares);\n }\n\n /// @inheritdoc IRequestManagerGatewayHandler\n function fulfillCancelDepositRequest(\n PoolId poolId,\n ShareClassId scId,\n address user,\n AssetId assetId,\n uint128 assets,\n uint128 fulfillment\n ) public auth {\n IAsyncVault vault_ = IAsyncVault(address(vault[poolId][scId][assetId]));\n\n AsyncInvestmentState storage state = investments[vault_][user];\n require(state.pendingCancelDepositRequest == true, NoPendingRequest());\n\n state.claimableCancelDepositRequest = state.claimableCancelDepositRequest + assets;\n state.pendingDepositRequest =\n state.pendingDepositRequest > fulfillment ? state.pendingDepositRequest - fulfillment : 0;\n\n if (state.pendingDepositRequest == 0) delete state.pendingCancelDepositRequest;\n\n vault_.onCancelDepositClaimable(user, assets);\n }\n\n /// @inheritdoc IRequestManagerGatewayHandler\n function fulfillCancelRedeemRequest(PoolId poolId, ShareClassId scId, address user, AssetId assetId, uint128 shares)\n public\n auth\n {\n IAsyncRedeemVault vault_ = IAsyncRedeemVault(address(vault[poolId][scId][assetId]));\n AsyncInvestmentState storage state = investments[vault_][user];\n require(state.pendingCancelRedeemRequest == true, NoPendingRequest());\n\n state.claimableCancelRedeemRequest = state.claimableCancelRedeemRequest + shares;\n state.pendingRedeemRequest = state.pendingRedeemRequest > shares ? state.pendingRedeemRequest - shares : 0;\n\n if (state.pendingRedeemRequest == 0) delete state.pendingCancelRedeemRequest;\n\n vault_.onCancelRedeemClaimable(user, shares);\n }\n\n //----------------------------------------------------------------------------------------------\n // Sync investment handlers\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IDepositManager\n function deposit(IBaseVault vault_, uint256 assets, address receiver, address controller)\n public\n auth\n returns (uint256 shares)\n {\n require(assets <= _maxDeposit(vault_, controller), ExceedsMaxDeposit());\n\n AsyncInvestmentState storage state = investments[vault_][controller];\n\n uint128 sharesUp = _assetToShareAmount(vault_, assets.toUint128(), state.depositPrice, MathLib.Rounding.Up);\n uint128 sharesDown = _assetToShareAmount(vault_, assets.toUint128(), state.depositPrice, MathLib.Rounding.Down);\n shares = uint256(sharesDown);\n _processDeposit(state, sharesUp, sharesDown, vault_, receiver);\n }\n\n /// @inheritdoc IDepositManager\n function mint(IBaseVault vault_, uint256 shares, address receiver, address controller)\n public\n auth\n returns (uint256 assets)\n {\n AsyncInvestmentState storage state = investments[vault_][controller];\n uint128 shares_ = shares.toUint128();\n\n assets = uint256(_shareToAssetAmount(vault_, shares_, state.depositPrice, MathLib.Rounding.Up));\n _processDeposit(state, shares_, shares_, vault_, receiver);\n }\n\n function _processDeposit(\n AsyncInvestmentState storage state,\n uint128 sharesUp,\n uint128 sharesDown,\n IBaseVault vault_,\n address receiver\n ) internal {\n require(sharesUp <= state.maxMint, ExceedsDepositLimits());\n state.maxMint = state.maxMint > sharesUp ? state.maxMint - sharesUp : 0;\n\n if (sharesDown > 0) {\n globalEscrow.authTransferTo(vault_.share(), receiver, sharesDown);\n }\n }\n\n /// @inheritdoc IRedeemManager\n function redeem(IBaseVault vault_, uint256 shares, address receiver, address controller)\n public\n auth\n returns (uint256 assets)\n {\n require(shares <= maxRedeem(vault_, controller), ExceedsMaxRedeem());\n\n AsyncInvestmentState storage state = investments[vault_][controller];\n\n uint128 assetsUp = _shareToAssetAmount(vault_, shares.toUint128(), state.redeemPrice, MathLib.Rounding.Up);\n uint128 assetsDown = _shareToAssetAmount(vault_, shares.toUint128(), state.redeemPrice, MathLib.Rounding.Down);\n _processRedeem(state, assetsUp, assetsDown, vault_, receiver, controller);\n assets = uint256(assetsDown);\n }\n\n /// @inheritdoc IRedeemManager\n function withdraw(IBaseVault vault_, uint256 assets, address receiver, address controller)\n public\n auth\n returns (uint256 shares)\n {\n AsyncInvestmentState storage state = investments[vault_][controller];\n uint128 assets_ = assets.toUint128();\n _processRedeem(state, assets_, assets_, vault_, receiver, controller);\n\n shares = uint256(_assetToShareAmount(vault_, assets_, state.redeemPrice, MathLib.Rounding.Up));\n }\n\n function _processRedeem(\n AsyncInvestmentState storage state,\n uint128 assetsUp,\n uint128 assetsDown,\n IBaseVault vault_,\n address receiver,\n address controller\n ) internal {\n if (controller != receiver) {\n require(\n _canTransfer(vault_, controller, receiver, convertToShares(vault_, assetsDown)), TransferNotAllowed()\n );\n }\n\n require(_canTransfer(vault_, receiver, address(0), convertToShares(vault_, assetsDown)), TransferNotAllowed());\n\n require(assetsUp <= state.maxWithdraw, ExceedsRedeemLimits());\n state.maxWithdraw = state.maxWithdraw > assetsUp ? state.maxWithdraw - assetsUp : 0;\n\n if (assetsDown > 0) {\n _withdraw(vault_, receiver, assetsDown);\n }\n }\n\n /// @dev Transfer funds from escrow to receiver and update holdings\n function _withdraw(IBaseVault vault_, address receiver, uint128 assets) internal {\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n\n PoolId poolId = vault_.poolId();\n ShareClassId scId = vault_.scId();\n\n poolEscrowProvider.escrow(poolId).reserveDecrease(scId, vaultDetails.asset, vaultDetails.tokenId, assets);\n balanceSheet.withdraw(poolId, scId, vaultDetails.asset, vaultDetails.tokenId, receiver, assets);\n }\n\n //----------------------------------------------------------------------------------------------\n // Cancellation claim handlers\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IAsyncDepositManager\n function claimCancelDepositRequest(IBaseVault vault_, address receiver, address controller)\n public\n auth\n returns (uint256 assets)\n {\n AsyncInvestmentState storage state = investments[vault_][controller];\n assets = state.claimableCancelDepositRequest;\n state.claimableCancelDepositRequest = 0;\n uint256 shares = convertToShares(vault_, assets);\n\n if (controller != receiver) {\n require(_canTransfer(vault_, controller, receiver, shares), TransferNotAllowed());\n }\n require(_canTransfer(vault_, receiver, address(0), shares), TransferNotAllowed());\n\n if (assets > 0) {\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n globalEscrow.authTransferTo(vaultDetails.asset, vaultDetails.tokenId, receiver, assets);\n }\n }\n\n /// @inheritdoc IAsyncRedeemManager\n function claimCancelRedeemRequest(IBaseVault vault_, address receiver, address controller)\n public\n auth\n returns (uint256 shares)\n {\n AsyncInvestmentState storage state = investments[vault_][controller];\n shares = state.claimableCancelRedeemRequest;\n state.claimableCancelRedeemRequest = 0;\n\n if (shares > 0) {\n globalEscrow.authTransferTo(vault_.share(), receiver, shares);\n }\n }\n\n //----------------------------------------------------------------------------------------------\n // View methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IDepositManager\n function maxDeposit(IBaseVault vault_, address user) public view returns (uint256 assets) {\n if (!_canTransfer(vault_, ESCROW_HOOK_ID, user, 0)) {\n return 0;\n }\n assets = uint256(_maxDeposit(vault_, user));\n }\n\n function _maxDeposit(IBaseVault vault_, address user) internal view returns (uint128 assets) {\n AsyncInvestmentState memory state = investments[vault_][user];\n\n assets = _shareToAssetAmount(vault_, state.maxMint, state.depositPrice, MathLib.Rounding.Down);\n }\n\n /// @inheritdoc IDepositManager\n function maxMint(IBaseVault vault_, address user) public view returns (uint256 shares) {\n if (!_canTransfer(vault_, ESCROW_HOOK_ID, user, 0)) {\n return 0;\n }\n shares = uint256(investments[vault_][user].maxMint);\n }\n\n /// @inheritdoc IRedeemManager\n function maxWithdraw(IBaseVault vault_, address user) public view returns (uint256 assets) {\n if (!_canTransfer(vault_, user, address(0), 0)) return 0;\n assets = uint256(investments[vault_][user].maxWithdraw);\n }\n\n /// @inheritdoc IRedeemManager\n function maxRedeem(IBaseVault vault_, address user) public view returns (uint256 shares) {\n if (!_canTransfer(vault_, user, address(0), 0)) return 0;\n AsyncInvestmentState memory state = investments[vault_][user];\n\n shares = uint256(_assetToShareAmount(vault_, state.maxWithdraw, state.redeemPrice, MathLib.Rounding.Down));\n }\n\n /// @inheritdoc IAsyncDepositManager\n function pendingDepositRequest(IBaseVault vault_, address user) public view returns (uint256 assets) {\n assets = uint256(investments[vault_][user].pendingDepositRequest);\n }\n\n /// @inheritdoc IAsyncRedeemManager\n function pendingRedeemRequest(IBaseVault vault_, address user) public view returns (uint256 shares) {\n shares = uint256(investments[vault_][user].pendingRedeemRequest);\n }\n\n /// @inheritdoc IAsyncDepositManager\n function pendingCancelDepositRequest(IBaseVault vault_, address user) public view returns (bool isPending) {\n isPending = investments[vault_][user].pendingCancelDepositRequest;\n }\n\n /// @inheritdoc IAsyncRedeemManager\n function pendingCancelRedeemRequest(IBaseVault vault_, address user) public view returns (bool isPending) {\n isPending = investments[vault_][user].pendingCancelRedeemRequest;\n }\n\n /// @inheritdoc IAsyncDepositManager\n function claimableCancelDepositRequest(IBaseVault vault_, address user) public view returns (uint256 assets) {\n assets = investments[vault_][user].claimableCancelDepositRequest;\n }\n\n /// @inheritdoc IAsyncRedeemManager\n function claimableCancelRedeemRequest(IBaseVault vault_, address user) public view returns (uint256 shares) {\n shares = investments[vault_][user].claimableCancelRedeemRequest;\n }\n\n //----------------------------------------------------------------------------------------------\n // Helpers\n //----------------------------------------------------------------------------------------------\n\n /// @dev Checks transfer restrictions for the vault shares. Sender (from) and receiver (to) have to both pass\n /// the restrictions for a successful share transfer.\n function _canTransfer(IBaseVault vault_, address from, address to, uint256 value) internal view returns (bool) {\n IShareToken share = IShareToken(vault_.share());\n return share.checkTransferRestriction(from, to, value);\n }\n\n function _assetToShareAmount(\n IBaseVault vault_,\n uint128 assets,\n uint256 priceAssetPerShare,\n MathLib.Rounding rounding\n ) internal view returns (uint128 shares) {\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n address shareToken = vault_.share();\n\n return PricingLib.assetToShareAmount(\n shareToken, vaultDetails.asset, vaultDetails.tokenId, assets, d18(priceAssetPerShare.toUint128()), rounding\n );\n }\n\n function _shareToAssetAmount(\n IBaseVault vault_,\n uint128 shares,\n uint256 priceAssetPerShare,\n MathLib.Rounding rounding\n ) internal view returns (uint128 assets) {\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n address shareToken = vault_.share();\n\n return PricingLib.shareToAssetAmount(\n shareToken, shares, vaultDetails.asset, vaultDetails.tokenId, d18(priceAssetPerShare.toUint128()), rounding\n );\n }\n\n function _calculatePriceAssetPerShare(IBaseVault vault_, uint128 shares, uint128 assets, MathLib.Rounding rounding)\n internal\n view\n returns (uint256 price)\n {\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n address shareToken = vault_.share();\n\n return PricingLib.calculatePriceAssetPerShare(\n shareToken, shares, vaultDetails.asset, vaultDetails.tokenId, assets, rounding\n );\n }\n}\n" + }, + "src/vaults/AsyncVault.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport \"src/misc/interfaces/IERC7540.sol\";\nimport \"src/misc/interfaces/IERC7575.sol\";\nimport {SafeTransferLib} from \"src/misc/libraries/SafeTransferLib.sol\";\nimport {IERC20} from \"src/misc/interfaces/IERC20.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nimport {IAsyncRedeemVault, VaultKind} from \"src/vaults/interfaces/IBaseVaults.sol\";\nimport {BaseVault, BaseAsyncRedeemVault} from \"src/vaults/BaseVaults.sol\";\nimport {IAsyncVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\nimport {IAsyncRequestManager} from \"src/vaults/interfaces/investments/IAsyncRequestManager.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\n\n/// @title AsyncVault\n/// @notice Asynchronous Tokenized Vault standard implementation for Centrifuge pools\n///\n/// @dev Each vault issues shares of Centrifuge share class tokens as restricted ERC-20 tokens\n/// against asset deposits based on the current share price.\n///\n/// ERC-7540 is an extension of the ERC-4626 standard by 'requestDeposit' & 'requestRedeem' methods, where\n/// deposit and redeem orders are submitted to the pools to be included in the execution of the following epoch.\n/// After execution users can use the deposit, mint, redeem and withdraw functions to get their shares\n/// and/or assets from the pools.\ncontract AsyncVault is BaseAsyncRedeemVault, IAsyncVault {\n constructor(\n PoolId poolId_,\n ShareClassId scId_,\n address asset_,\n IShareToken token_,\n address root_,\n IAsyncRequestManager manager_\n ) BaseVault(poolId_, scId_, asset_, token_, root_, manager_) BaseAsyncRedeemVault(manager_) {}\n\n //----------------------------------------------------------------------------------------------\n // ERC-7540 deposit\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC7540Deposit\n function requestDeposit(uint256 assets, address controller, address owner) public returns (uint256) {\n require(owner == msg.sender || isOperator[owner][msg.sender], InvalidOwner());\n require(IERC20(asset).balanceOf(owner) >= assets, InsufficientBalance());\n\n require(asyncManager().requestDeposit(this, assets, controller, owner, msg.sender), RequestDepositFailed());\n SafeTransferLib.safeTransferFrom(asset, owner, address(manager.globalEscrow()), assets);\n\n emit DepositRequest(controller, owner, REQUEST_ID, msg.sender, assets);\n return REQUEST_ID;\n }\n\n /// @inheritdoc IERC7540Deposit\n function pendingDepositRequest(uint256, address controller) public view returns (uint256 pendingAssets) {\n pendingAssets = asyncManager().pendingDepositRequest(this, controller);\n }\n\n /// @inheritdoc IERC7540Deposit\n function claimableDepositRequest(uint256, address controller) external view returns (uint256 claimableAssets) {\n claimableAssets = maxDeposit(controller);\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-7887\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC7887Deposit\n function cancelDepositRequest(uint256, address controller) external {\n _validateController(controller);\n asyncManager().cancelDepositRequest(this, controller, msg.sender);\n emit CancelDepositRequest(controller, REQUEST_ID, msg.sender);\n }\n\n /// @inheritdoc IERC7887Deposit\n function pendingCancelDepositRequest(uint256, address controller) public view returns (bool isPending) {\n isPending = asyncManager().pendingCancelDepositRequest(this, controller);\n }\n\n /// @inheritdoc IERC7887Deposit\n function claimableCancelDepositRequest(uint256, address controller) public view returns (uint256 claimableAssets) {\n claimableAssets = asyncManager().claimableCancelDepositRequest(this, controller);\n }\n\n /// @inheritdoc IERC7887Deposit\n function claimCancelDepositRequest(uint256, address receiver, address controller)\n external\n returns (uint256 assets)\n {\n _validateController(controller);\n assets = asyncManager().claimCancelDepositRequest(this, receiver, controller);\n emit CancelDepositClaim(controller, receiver, REQUEST_ID, msg.sender, assets);\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-165\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC165\n function supportsInterface(bytes4 interfaceId) public pure override(BaseAsyncRedeemVault, IERC165) returns (bool) {\n return interfaceId == type(IERC7540Deposit).interfaceId || interfaceId == type(IERC7887Deposit).interfaceId\n || super.supportsInterface(interfaceId);\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-7540 claim\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC7575\n function maxDeposit(address controller) public view returns (uint256 maxAssets) {\n maxAssets = asyncManager().maxDeposit(this, controller);\n }\n\n /// @inheritdoc IERC7540Deposit\n function deposit(uint256 assets, address receiver, address controller) public returns (uint256 shares) {\n _validateController(controller);\n shares = asyncManager().deposit(this, assets, receiver, controller);\n emit Deposit(controller, receiver, assets, shares);\n }\n\n /// @inheritdoc IERC7575\n /// @notice When claiming deposit requests using deposit(), there can be some precision loss leading to dust.\n /// It is recommended to use mint() to claim deposit requests instead.\n function deposit(uint256 assets, address receiver) external returns (uint256 shares) {\n shares = deposit(assets, receiver, msg.sender);\n }\n\n /// @inheritdoc IERC7575\n function maxMint(address controller) public view returns (uint256 maxShares) {\n maxShares = asyncManager().maxMint(this, controller);\n }\n\n /// @inheritdoc IERC7540Deposit\n function mint(uint256 shares, address receiver, address controller) public returns (uint256 assets) {\n _validateController(controller);\n assets = asyncManager().mint(this, shares, receiver, controller);\n emit Deposit(controller, receiver, assets, shares);\n }\n\n /// @inheritdoc IERC7575\n function mint(uint256 shares, address receiver) public returns (uint256 assets) {\n assets = mint(shares, receiver, msg.sender);\n }\n\n /// @dev Strongly-typed accessor to the generic async redeem manager\n function asyncManager() public view returns (IAsyncRequestManager) {\n return IAsyncRequestManager(address(IAsyncRedeemVault(this).asyncRedeemManager()));\n }\n\n /// @dev Preview functions for ERC-7540 vaults revert\n function previewDeposit(uint256) external pure returns (uint256) {\n revert();\n }\n\n /// @dev Preview functions for ERC-7540 vaults revert\n function previewMint(uint256) external pure returns (uint256) {\n revert();\n }\n\n //----------------------------------------------------------------------------------------------\n // Event emitters\n //----------------------------------------------------------------------------------------------\n\n function onDepositClaimable(address controller, uint256 assets, uint256 shares) public virtual auth {\n emit DepositClaimable(controller, REQUEST_ID, assets, shares);\n }\n\n function onCancelDepositClaimable(address controller, uint256 assets) public virtual auth {\n emit CancelDepositClaimable(controller, REQUEST_ID, assets);\n }\n\n //----------------------------------------------------------------------------------------------\n // IBaseVault view\n //----------------------------------------------------------------------------------------------\n\n function vaultKind() public pure returns (VaultKind vaultKind_) {\n return VaultKind.Async;\n }\n}\n" + }, + "src/vaults/BalanceSheet.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {IAuth} from \"src/misc/interfaces/IAuth.sol\";\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {D18, d18} from \"src/misc/types/D18.sol\";\nimport {IERC6909} from \"src/misc/interfaces/IERC6909.sol\";\nimport {Recoverable} from \"src/misc/Recoverable.sol\";\nimport {SafeTransferLib} from \"src/misc/libraries/SafeTransferLib.sol\";\nimport {TransientStorageLib} from \"src/misc/libraries/TransientStorageLib.sol\";\n\nimport {IRoot} from \"src/common/interfaces/IRoot.sol\";\nimport {IGateway} from \"src/common/interfaces/IGateway.sol\";\nimport {MessageLib, UpdateContractType} from \"src/common/libraries/MessageLib.sol\";\nimport {IVaultMessageSender} from \"../common/interfaces/IGatewaySenders.sol\";\nimport {IBalanceSheetGatewayHandler} from \"src/common/interfaces/IGatewayHandlers.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\n\nimport {IPoolManager} from \"src/vaults/interfaces/IPoolManager.sol\";\nimport {IBalanceSheet, QueueAmount} from \"src/vaults/interfaces/IBalanceSheet.sol\";\nimport {IPoolEscrow} from \"src/vaults/interfaces/IEscrow.sol\";\nimport {IUpdateContract} from \"src/vaults/interfaces/IUpdateContract.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\nimport {IPoolEscrowProvider} from \"src/vaults/interfaces/factories/IPoolEscrowFactory.sol\";\n\n/// @title Balance Sheet\n/// @notice Management contract that integrates all balance sheet functions of a pool:\n/// - Issuing and revoking shares\n/// - Depositing and withdrawing assets\n/// - Force transferring shares\n///\n/// Share and asset updates to the Hub are optionally queued, to reduce the cost\n/// per transaction. Dequeuing can be triggered locally by the manager or from the Hub.\ncontract BalanceSheet is Auth, Recoverable, IBalanceSheet, IBalanceSheetGatewayHandler, IUpdateContract {\n using MathLib for *;\n using CastLib for bytes32;\n\n IRoot public immutable root;\n\n IPoolManager public poolManager;\n IVaultMessageSender public sender;\n IPoolEscrowProvider public poolEscrowProvider;\n\n mapping(PoolId => mapping(address => bool)) public manager;\n mapping(PoolId poolId => mapping(ShareClassId scId => bool)) public queueEnabled;\n mapping(PoolId poolId => mapping(ShareClassId scId => QueueAmount)) public queuedShares;\n mapping(PoolId poolId => mapping(ShareClassId scId => mapping(AssetId assetId => QueueAmount))) public queuedAssets;\n\n constructor(IRoot root_, address deployer) Auth(deployer) {\n root = root_;\n }\n\n /// @dev Check if the msg.sender is ward or a manager\n modifier authOrManager(PoolId poolId) {\n require(wards[msg.sender] == 1 || manager[poolId][msg.sender], IAuth.NotAuthorized());\n _;\n }\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n function file(bytes32 what, address data) external auth {\n if (what == \"poolManager\") poolManager = IPoolManager(data);\n else if (what == \"sender\") sender = IVaultMessageSender(data);\n else if (what == \"poolEscrowProvider\") poolEscrowProvider = IPoolEscrowProvider(data);\n else revert FileUnrecognizedParam();\n emit File(what, data);\n }\n\n function update(PoolId poolId, ShareClassId, /* scId */ bytes calldata payload) external auth {\n uint8 kind = uint8(MessageLib.updateContractType(payload));\n\n if (kind == uint8(UpdateContractType.UpdateManager)) {\n MessageLib.UpdateContractUpdateManager memory m = MessageLib.deserializeUpdateContractUpdateManager(payload);\n address who = m.who.toAddress();\n\n manager[poolId][who] = m.canManage;\n emit UpdateManager(poolId, who, m.canManage);\n } else {\n revert UnknownUpdateContractType();\n }\n }\n\n //----------------------------------------------------------------------------------------------\n // Management functions\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IBalanceSheet\n function deposit(PoolId poolId, ShareClassId scId, address asset, uint256 tokenId, address owner, uint128 amount)\n external\n authOrManager(poolId)\n {\n AssetId assetId = poolManager.assetToId(asset, tokenId);\n _noteDeposit(poolId, scId, assetId, asset, tokenId, owner, amount);\n _executeDeposit(poolId, asset, tokenId, owner, amount);\n }\n\n /// @inheritdoc IBalanceSheet\n /// @dev This function is mostly useful to keep higher level integrations CEI adherent.\n function noteDeposit(\n PoolId poolId,\n ShareClassId scId,\n address asset,\n uint256 tokenId,\n address owner,\n uint128 amount\n ) external authOrManager(poolId) {\n AssetId assetId = poolManager.assetToId(asset, tokenId);\n _noteDeposit(poolId, scId, assetId, asset, tokenId, owner, amount);\n }\n\n /// @inheritdoc IBalanceSheet\n function withdraw(\n PoolId poolId,\n ShareClassId scId,\n address asset,\n uint256 tokenId,\n address receiver,\n uint128 amount\n ) external authOrManager(poolId) {\n AssetId assetId = poolManager.assetToId(asset, tokenId);\n _withdraw(poolId, scId, assetId, asset, tokenId, receiver, amount);\n }\n\n /// @inheritdoc IBalanceSheet\n function issue(PoolId poolId, ShareClassId scId, address to, uint128 shares) external authOrManager(poolId) {\n _issue(poolId, scId, to, shares);\n }\n\n /// @inheritdoc IBalanceSheet\n function revoke(PoolId poolId, ShareClassId scId, address from, uint128 shares) external authOrManager(poolId) {\n _noteRevoke(poolId, scId, from, shares);\n _executeRevoke(poolId, scId, from, shares);\n }\n\n /// @inheritdoc IBalanceSheet\n /// @dev This function is mostly useful to keep higher level integrations CEI adherent.\n function noteRevoke(PoolId poolId, ShareClassId scId, address from, uint128 shares)\n external\n authOrManager(poolId)\n {\n _noteRevoke(poolId, scId, from, shares);\n }\n\n /// @inheritdoc IBalanceSheet\n function transferSharesFrom(PoolId poolId, ShareClassId scId, address from, address to, uint256 amount)\n external\n authOrManager(poolId)\n {\n require(!root.endorsed(from), CannotTransferFromEndorsedContract());\n IShareToken token = IShareToken(poolManager.shareToken(poolId, scId));\n token.authTransferFrom(from, from, to, amount);\n }\n\n /// @inheritdoc IBalanceSheet\n function overridePricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId, D18 value)\n external\n authOrManager(poolId)\n {\n TransientStorageLib.tstore(keccak256(abi.encode(\"pricePoolPerAsset\", poolId, scId, assetId)), value.raw());\n TransientStorageLib.tstore(keccak256(abi.encode(\"pricePoolPerAssetIsSet\", poolId, scId, assetId)), true);\n }\n\n /// @inheritdoc IBalanceSheet\n function overridePricePoolPerShare(PoolId poolId, ShareClassId scId, D18 value) external authOrManager(poolId) {\n TransientStorageLib.tstore(keccak256(abi.encode(\"pricePoolPerShare\", poolId, scId)), value.raw());\n TransientStorageLib.tstore(keccak256(abi.encode(\"pricePoolPerShareIsSet\", poolId, scId)), true);\n }\n\n //----------------------------------------------------------------------------------------------\n // Gateway handlers\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IBalanceSheetGatewayHandler\n function triggerDeposit(PoolId poolId, ShareClassId scId, AssetId assetId, address owner, uint128 amount)\n external\n auth\n {\n (address asset, uint256 tokenId) = poolManager.idToAsset(assetId);\n _noteDeposit(poolId, scId, assetId, asset, tokenId, owner, amount);\n _executeDeposit(poolId, asset, tokenId, owner, amount);\n }\n\n /// @inheritdoc IBalanceSheetGatewayHandler\n function triggerWithdraw(PoolId poolId, ShareClassId scId, AssetId assetId, address receiver, uint128 amount)\n external\n auth\n {\n (address asset, uint256 tokenId) = poolManager.idToAsset(assetId);\n _withdraw(poolId, scId, assetId, asset, tokenId, receiver, amount);\n }\n\n /// @inheritdoc IBalanceSheetGatewayHandler\n function triggerIssueShares(PoolId poolId, ShareClassId scId, address receiver, uint128 shares) external auth {\n _issue(poolId, scId, receiver, shares);\n }\n\n /// @inheritdoc IBalanceSheetGatewayHandler\n function setQueue(PoolId poolId, ShareClassId scId, bool enabled) external auth {\n queueEnabled[poolId][scId] = enabled;\n }\n\n /// @inheritdoc IBalanceSheetGatewayHandler\n function submitQueuedAssets(PoolId poolId, ShareClassId scId, AssetId assetId) external authOrManager(poolId) {\n _submitQueuedAssets(poolId, scId, assetId);\n }\n\n /// @inheritdoc IBalanceSheetGatewayHandler\n function submitQueuedShares(PoolId poolId, ShareClassId scId) external authOrManager(poolId) {\n _submitQueuedShares(poolId, scId);\n }\n\n //----------------------------------------------------------------------------------------------\n // Internal\n //----------------------------------------------------------------------------------------------\n\n function _noteDeposit(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n address asset,\n uint256 tokenId,\n address owner,\n uint128 amount\n ) internal {\n IPoolEscrow escrow = poolEscrowProvider.escrow(poolId);\n escrow.deposit(scId, asset, tokenId, amount);\n\n D18 pricePoolPerAsset_ = _pricePoolPerAsset(poolId, scId, assetId);\n emit Deposit(poolId, scId, asset, tokenId, owner, amount, pricePoolPerAsset_);\n\n if (queueEnabled[poolId][scId]) {\n queuedAssets[poolId][scId][assetId].increase += amount;\n } else {\n sender.sendUpdateHoldingAmount(poolId, scId, assetId, owner, amount, pricePoolPerAsset_, true);\n }\n }\n\n function _executeDeposit(PoolId poolId, address asset, uint256 tokenId, address owner, uint128 amount) internal {\n IPoolEscrow escrow = poolEscrowProvider.escrow(poolId);\n if (tokenId == 0) {\n SafeTransferLib.safeTransferFrom(asset, owner, address(escrow), amount);\n } else {\n IERC6909(asset).transferFrom(owner, address(escrow), tokenId, amount);\n }\n }\n\n function _withdraw(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n address asset,\n uint256 tokenId,\n address receiver,\n uint128 amount\n ) internal {\n IPoolEscrow escrow = poolEscrowProvider.escrow(poolId);\n escrow.withdraw(scId, asset, tokenId, amount);\n\n D18 pricePoolPerAsset_ = _pricePoolPerAsset(poolId, scId, assetId);\n emit Withdraw(poolId, scId, asset, tokenId, receiver, amount, pricePoolPerAsset_);\n\n if (queueEnabled[poolId][scId]) {\n queuedAssets[poolId][scId][assetId].decrease += amount;\n } else {\n sender.sendUpdateHoldingAmount(poolId, scId, assetId, receiver, amount, pricePoolPerAsset_, false);\n }\n\n escrow.authTransferTo(asset, tokenId, receiver, amount);\n }\n\n function _issue(PoolId poolId, ShareClassId scId, address to, uint128 shares) internal {\n emit Issue(poolId, scId, to, _pricePoolPerShare(poolId, scId), shares);\n\n if (queueEnabled[poolId][scId]) {\n queuedShares[poolId][scId].increase += shares;\n } else {\n sender.sendUpdateShares(poolId, scId, shares, true);\n }\n\n IShareToken token = poolManager.shareToken(poolId, scId);\n token.mint(to, shares);\n }\n\n function _noteRevoke(PoolId poolId, ShareClassId scId, address from, uint128 shares) internal {\n emit Revoke(poolId, scId, from, _pricePoolPerShare(poolId, scId), shares);\n\n if (queueEnabled[poolId][scId]) {\n queuedShares[poolId][scId].decrease += shares;\n } else {\n sender.sendUpdateShares(poolId, scId, shares, false);\n }\n }\n\n function _executeRevoke(PoolId poolId, ShareClassId scId, address from, uint128 shares) internal {\n IShareToken token = poolManager.shareToken(poolId, scId);\n token.authTransferFrom(from, from, address(this), shares);\n token.burn(address(this), shares);\n }\n\n function _submitQueuedShares(PoolId poolId, ShareClassId scId) internal {\n QueueAmount storage queue = queuedShares[poolId][scId];\n\n if (queue.increase > queue.decrease) {\n sender.sendUpdateShares(poolId, scId, queue.increase - queue.decrease, true);\n } else if (queue.decrease > queue.increase) {\n sender.sendUpdateShares(poolId, scId, queue.decrease - queue.increase, false);\n }\n\n queue.increase = 0;\n queue.decrease = 0;\n }\n\n function _submitQueuedAssets(PoolId poolId, ShareClassId scId, AssetId assetId) internal {\n QueueAmount storage queue = queuedAssets[poolId][scId][assetId];\n\n D18 pricePoolPerAsset = _pricePoolPerAsset(poolId, scId, assetId);\n if (queue.increase > queue.decrease) {\n sender.sendUpdateHoldingAmount(\n poolId, scId, assetId, address(0), queue.increase - queue.decrease, pricePoolPerAsset, true\n );\n } else if (queue.decrease > queue.increase) {\n sender.sendUpdateHoldingAmount(\n poolId, scId, assetId, address(0), queue.decrease - queue.increase, pricePoolPerAsset, false\n );\n }\n\n queue.increase = 0;\n queue.decrease = 0;\n }\n\n function _pricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId) internal view returns (D18) {\n if (TransientStorageLib.tloadBool(keccak256(abi.encode(\"pricePoolPerAssetIsSet\", poolId, scId, assetId)))) {\n return\n d18(TransientStorageLib.tloadUint128(keccak256(abi.encode(\"pricePoolPerAsset\", poolId, scId, assetId))));\n }\n\n D18 pricePoolPerAsset = poolManager.pricePoolPerAsset(poolId, scId, assetId, true);\n return pricePoolPerAsset;\n }\n\n function _pricePoolPerShare(PoolId poolId, ShareClassId scId) internal view returns (D18) {\n if (TransientStorageLib.tloadBool(keccak256(abi.encode(\"pricePoolPerShareIsSet\", poolId, scId)))) {\n return d18(TransientStorageLib.tloadUint128(keccak256(abi.encode(\"pricePoolPerShare\", poolId, scId))));\n }\n\n D18 pricePoolPerShare = poolManager.pricePoolPerShare(poolId, scId, true);\n return pricePoolPerShare;\n }\n}\n" + }, + "src/vaults/BaseRequestManager.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {D18} from \"src/misc/types/D18.sol\";\nimport {Recoverable} from \"src/misc/Recoverable.sol\";\nimport {IAuth} from \"src/misc/interfaces/IAuth.sol\";\n\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {PricingLib} from \"src/common/libraries/PricingLib.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nimport {IPoolManager, VaultDetails} from \"src/vaults/interfaces/IPoolManager.sol\";\nimport {IBaseRequestManager} from \"src/vaults/interfaces/investments/IBaseRequestManager.sol\";\nimport {IPoolEscrowProvider} from \"src/vaults/interfaces/factories/IPoolEscrowFactory.sol\";\nimport {IBaseVault, VaultKind} from \"src/vaults/interfaces/IBaseVaults.sol\";\nimport {IPoolEscrow, IEscrow} from \"src/vaults/interfaces/IEscrow.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\n\nabstract contract BaseRequestManager is Auth, Recoverable, IBaseRequestManager {\n using MathLib for uint256;\n\n address public immutable root;\n IEscrow public immutable globalEscrow;\n\n IPoolManager public poolManager;\n IPoolEscrowProvider public poolEscrowProvider;\n\n mapping(PoolId poolId => mapping(ShareClassId scId => mapping(AssetId assetId => IBaseVault vault))) public vault;\n\n constructor(IEscrow globalEscrow_, address root_, address deployer) Auth(deployer) {\n globalEscrow = globalEscrow_;\n root = root_;\n }\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IBaseRequestManager\n function file(bytes32 what, address data) external virtual auth {\n if (what == \"poolManager\") poolManager = IPoolManager(data);\n else if (what == \"poolEscrowProvider\") poolEscrowProvider = IPoolEscrowProvider(data);\n else revert FileUnrecognizedParam();\n emit File(what, data);\n }\n\n /// @inheritdoc IBaseRequestManager\n function addVault(PoolId poolId, ShareClassId scId, IBaseVault vault_, address asset_, AssetId assetId)\n public\n virtual\n auth\n {\n address token = vault_.share();\n\n require(vault_.asset() == asset_, AssetMismatch());\n require(address(vault[poolId][scId][assetId]) == address(0), VaultAlreadyExists());\n\n vault[poolId][scId][assetId] = IBaseVault(address(vault_));\n IAuth(token).rely(address(vault_));\n IShareToken(token).updateVault(vault_.asset(), address(vault_));\n rely(address(vault_));\n }\n\n /// @inheritdoc IBaseRequestManager\n function removeVault(PoolId poolId, ShareClassId scId, IBaseVault vault_, address asset_, AssetId assetId)\n public\n virtual\n auth\n {\n address token = vault_.share();\n\n require(vault_.asset() == asset_, AssetMismatch());\n require(address(vault[poolId][scId][assetId]) != address(0), VaultDoesNotExist());\n\n delete vault[poolId][scId][assetId];\n\n IAuth(token).deny(address(vault_));\n IShareToken(token).updateVault(vault_.asset(), address(0));\n deny(address(vault_));\n }\n\n //----------------------------------------------------------------------------------------------\n // View methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IBaseRequestManager\n function convertToShares(IBaseVault vault_, uint256 assets) public view virtual returns (uint256 shares) {\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n (D18 pricePoolPerAsset, D18 pricePoolPerShare) =\n poolManager.pricesPoolPer(vault_.poolId(), vault_.scId(), vaultDetails.assetId, false);\n\n return _assetToShareAmount(\n vault_, vaultDetails, assets, pricePoolPerAsset, pricePoolPerShare, MathLib.Rounding.Down\n );\n }\n\n /// @inheritdoc IBaseRequestManager\n function convertToAssets(IBaseVault vault_, uint256 shares) public view virtual returns (uint256 assets) {\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n (D18 pricePoolPerAsset, D18 pricePoolPerShare) =\n poolManager.pricesPoolPer(vault_.poolId(), vault_.scId(), vaultDetails.assetId, false);\n\n return _shareToAssetAmount(\n vault_, vaultDetails, shares, pricePoolPerAsset, pricePoolPerShare, MathLib.Rounding.Down\n );\n }\n\n /// @inheritdoc IBaseRequestManager\n function priceLastUpdated(IBaseVault vault_) public view virtual returns (uint64 lastUpdated) {\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n\n (uint64 shareLastUpdated,,) = poolManager.markersPricePoolPerShare(vault_.poolId(), vault_.scId());\n (uint64 assetLastUpdated,,) =\n poolManager.markersPricePoolPerAsset(vault_.poolId(), vault_.scId(), vaultDetails.assetId);\n\n // Choose the latest update to be the marker\n lastUpdated = MathLib.max(shareLastUpdated, assetLastUpdated).toUint64();\n }\n\n /// @inheritdoc IBaseRequestManager\n function poolEscrow(PoolId poolId) public view returns (IPoolEscrow) {\n return poolEscrowProvider.escrow(poolId);\n }\n\n /// @inheritdoc IBaseRequestManager\n function vaultByAssetId(PoolId poolId, ShareClassId scId, AssetId assetId) public view returns (IBaseVault) {\n return vault[poolId][scId][assetId];\n }\n\n function _assetToShareAmount(\n IBaseVault vault_,\n VaultDetails memory vaultDetails,\n uint256 assets,\n D18 pricePoolPerAsset,\n D18 pricePoolPerShare,\n MathLib.Rounding rounding\n ) internal view returns (uint256 shares) {\n return PricingLib.assetToShareAmount(\n vault_.share(),\n vaultDetails.asset,\n vaultDetails.tokenId,\n assets.toUint128(),\n pricePoolPerAsset,\n pricePoolPerShare,\n rounding\n );\n }\n\n function _shareToAssetAmount(\n IBaseVault vault_,\n VaultDetails memory vaultDetails,\n uint256 shares,\n D18 pricePoolPerAsset,\n D18 pricePoolPerShare,\n MathLib.Rounding rounding\n ) internal view returns (uint256 assets) {\n return PricingLib.shareToAssetAmount(\n vault_.share(),\n shares.toUint128(),\n vaultDetails.asset,\n vaultDetails.tokenId,\n pricePoolPerAsset,\n pricePoolPerShare,\n rounding\n );\n }\n}\n" + }, + "src/vaults/BaseVaults.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport \"src/misc/interfaces/IERC7540.sol\";\nimport \"src/misc/interfaces/IERC7575.sol\";\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {IERC20Metadata} from \"src/misc/interfaces/IERC20.sol\";\nimport {EIP712Lib} from \"src/misc/libraries/EIP712Lib.sol\";\nimport {SignatureLib} from \"src/misc/libraries/SignatureLib.sol\";\nimport {SafeTransferLib} from \"src/misc/libraries/SafeTransferLib.sol\";\nimport {Recoverable} from \"src/misc/Recoverable.sol\";\n\nimport {IRoot} from \"src/common/interfaces/IRoot.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nimport {IBaseVault, IAsyncRedeemVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\nimport {IERC7575} from \"src/misc/interfaces/IERC7575.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\nimport {IAsyncRedeemManager} from \"src/vaults/interfaces/investments/IAsyncRedeemManager.sol\";\nimport {ISyncDepositManager} from \"src/vaults/interfaces/investments/ISyncDepositManager.sol\";\nimport {IBaseRequestManager} from \"src/vaults/interfaces/investments/IBaseRequestManager.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\n\nabstract contract BaseVault is Auth, Recoverable, IBaseVault {\n /// @dev Requests for Centrifuge pool are non-fungible and all have ID = 0\n uint256 internal constant REQUEST_ID = 0;\n\n IRoot public immutable root;\n /// @dev this naming MUST NEVER change - due to legacy v2 vaults\n IBaseRequestManager public manager;\n\n /// @inheritdoc IBaseVault\n PoolId public immutable poolId;\n /// @inheritdoc IBaseVault\n ShareClassId public immutable scId;\n\n /// @inheritdoc IERC7575\n address public immutable asset;\n\n /// @inheritdoc IERC7575\n address public immutable share;\n uint8 internal immutable _shareDecimals;\n\n /// --- ERC7741 ---\n bytes32 private immutable nameHash;\n bytes32 private immutable versionHash;\n uint256 public immutable deploymentChainId;\n bytes32 private immutable _DOMAIN_SEPARATOR;\n bytes32 public constant AUTHORIZE_OPERATOR_TYPEHASH =\n keccak256(\"AuthorizeOperator(address controller,address operator,bool approved,bytes32 nonce,uint256 deadline)\");\n\n /// @inheritdoc IERC7741\n mapping(address controller => mapping(bytes32 nonce => bool used)) public authorizations;\n\n /// @inheritdoc IERC7540Operator\n mapping(address => mapping(address => bool)) public isOperator;\n\n constructor(\n PoolId poolId_,\n ShareClassId scId_,\n address asset_,\n IShareToken token_,\n address root_,\n IBaseRequestManager manager_\n ) Auth(msg.sender) {\n poolId = poolId_;\n scId = scId_;\n asset = asset_;\n share = address(token_);\n _shareDecimals = IERC20Metadata(share).decimals();\n root = IRoot(root_);\n manager = IBaseRequestManager(manager_);\n\n nameHash = keccak256(bytes(\"Centrifuge\"));\n versionHash = keccak256(bytes(\"1\"));\n deploymentChainId = block.chainid;\n _DOMAIN_SEPARATOR = EIP712Lib.calculateDomainSeparator(nameHash, versionHash);\n }\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n function file(bytes32 what, address data) external virtual auth {\n if (what == \"manager\") manager = IBaseRequestManager(data);\n else revert FileUnrecognizedParam();\n emit File(what, data);\n }\n\n /// @inheritdoc IERC7540Operator\n function setOperator(address operator, bool approved) public virtual returns (bool success) {\n require(msg.sender != operator, CannotSetSelfAsOperator());\n isOperator[msg.sender][operator] = approved;\n emit OperatorSet(msg.sender, operator, approved);\n success = true;\n }\n\n /// @inheritdoc IBaseVault\n function setEndorsedOperator(address owner, bool approved) public virtual {\n require(msg.sender != owner, CannotSetSelfAsOperator());\n require(root.endorsed(msg.sender), NotEndorsed());\n isOperator[owner][msg.sender] = approved;\n emit OperatorSet(owner, msg.sender, approved);\n }\n\n /// @inheritdoc IERC7741\n function DOMAIN_SEPARATOR() public view returns (bytes32) {\n return block.chainid == deploymentChainId\n ? _DOMAIN_SEPARATOR\n : EIP712Lib.calculateDomainSeparator(nameHash, versionHash);\n }\n\n /// @inheritdoc IERC7741\n function authorizeOperator(\n address controller,\n address operator,\n bool approved,\n bytes32 nonce,\n uint256 deadline,\n bytes memory signature\n ) external returns (bool success) {\n require(controller != operator, CannotSetSelfAsOperator());\n require(block.timestamp <= deadline, ExpiredAuthorization());\n require(!authorizations[controller][nonce], AlreadyUsedAuthorization());\n\n authorizations[controller][nonce] = true;\n\n bytes32 digest = keccak256(\n abi.encodePacked(\n \"\\x19\\x01\",\n DOMAIN_SEPARATOR(),\n keccak256(abi.encode(AUTHORIZE_OPERATOR_TYPEHASH, controller, operator, approved, nonce, deadline))\n )\n );\n\n require(SignatureLib.isValidSignature(controller, digest, signature), InvalidAuthorization());\n\n isOperator[controller][operator] = approved;\n emit OperatorSet(controller, operator, approved);\n\n success = true;\n }\n\n /// @inheritdoc IERC7741\n function invalidateNonce(bytes32 nonce) external {\n authorizations[msg.sender][nonce] = true;\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-165\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC165\n function supportsInterface(bytes4 interfaceId) public pure virtual override returns (bool) {\n return interfaceId == type(IERC7540Operator).interfaceId || interfaceId == type(IERC7741).interfaceId\n || interfaceId == type(IERC7714).interfaceId || interfaceId == type(IERC7575).interfaceId\n || interfaceId == type(IERC165).interfaceId;\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-4626\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC7575\n function totalAssets() external view returns (uint256) {\n return convertToAssets(IERC20Metadata(share).totalSupply());\n }\n\n /// @inheritdoc IERC7575\n /// @notice The calculation is based on the token price from the most recent epoch retrieved from Centrifuge.\n /// The actual conversion MAY change between order submission and execution.\n function convertToShares(uint256 assets) public view returns (uint256 shares) {\n shares = manager.convertToShares(this, assets);\n }\n\n /// @inheritdoc IERC7575\n /// @notice The calculation is based on the token price from the most recent epoch retrieved from Centrifuge.\n /// The actual conversion MAY change between order submission and execution.\n function convertToAssets(uint256 shares) public view returns (uint256 assets) {\n assets = manager.convertToAssets(this, shares);\n }\n\n //----------------------------------------------------------------------------------------------\n // Helpers\n //----------------------------------------------------------------------------------------------\n\n /// @notice Price of 1 unit of share, quoted in the decimals of the asset.\n function pricePerShare() external view returns (uint256) {\n return convertToAssets(10 ** _shareDecimals);\n }\n\n /// @notice Returns timestamp of the last share price update.\n function priceLastUpdated() external view returns (uint64) {\n return manager.priceLastUpdated(this);\n }\n\n /// @inheritdoc IERC7714\n function isPermissioned(address controller) external view returns (bool) {\n return IShareToken(share).checkTransferRestriction(address(0), controller, 0);\n }\n\n /// @notice Ensures msg.sender can operate on behalf of controller.\n function _validateController(address controller) internal view {\n require(controller == msg.sender || isOperator[controller][msg.sender], InvalidController());\n }\n}\n\nabstract contract BaseAsyncRedeemVault is BaseVault, IAsyncRedeemVault {\n IAsyncRedeemManager public asyncRedeemManager;\n\n constructor(IAsyncRedeemManager asyncRequestManager_) {\n asyncRedeemManager = asyncRequestManager_;\n }\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n function file(bytes32 what, address data) external virtual override auth {\n if (what == \"manager\") manager = IBaseRequestManager(data);\n else if (what == \"asyncRedeemManager\") asyncRedeemManager = IAsyncRedeemManager(data);\n else revert FileUnrecognizedParam();\n emit File(what, data);\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-7540 redeem\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC7540Redeem\n function requestRedeem(uint256 shares, address controller, address owner) public returns (uint256) {\n require(IShareToken(share).balanceOf(owner) >= shares, InsufficientBalance());\n\n // If msg.sender is operator of owner, the transfer is executed as if\n // the sender is the owner, to bypass the allowance check\n address sender = isOperator[owner][msg.sender] ? owner : msg.sender;\n\n require(asyncRedeemManager.requestRedeem(this, shares, controller, owner, sender), RequestRedeemFailed());\n IShareToken(share).authTransferFrom(sender, owner, address(manager.globalEscrow()), shares);\n\n emit RedeemRequest(controller, owner, REQUEST_ID, msg.sender, shares);\n return REQUEST_ID;\n }\n\n /// @inheritdoc IERC7540Redeem\n function pendingRedeemRequest(uint256, address controller) public view returns (uint256 pendingShares) {\n pendingShares = asyncRedeemManager.pendingRedeemRequest(this, controller);\n }\n\n /// @inheritdoc IERC7540Redeem\n function claimableRedeemRequest(uint256, address controller) external view returns (uint256 claimableShares) {\n claimableShares = maxRedeem(controller);\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-7887\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC7887Redeem\n function cancelRedeemRequest(uint256, address controller) external {\n _validateController(controller);\n asyncRedeemManager.cancelRedeemRequest(this, controller, msg.sender);\n emit CancelRedeemRequest(controller, REQUEST_ID, msg.sender);\n }\n\n /// @inheritdoc IERC7887Redeem\n function pendingCancelRedeemRequest(uint256, address controller) public view returns (bool isPending) {\n isPending = asyncRedeemManager.pendingCancelRedeemRequest(this, controller);\n }\n\n /// @inheritdoc IERC7887Redeem\n function claimableCancelRedeemRequest(uint256, address controller) public view returns (uint256 claimableShares) {\n claimableShares = asyncRedeemManager.claimableCancelRedeemRequest(this, controller);\n }\n\n /// @inheritdoc IERC7887Redeem\n function claimCancelRedeemRequest(uint256, address receiver, address controller)\n external\n returns (uint256 shares)\n {\n _validateController(controller);\n shares = asyncRedeemManager.claimCancelRedeemRequest(this, receiver, controller);\n emit CancelRedeemClaim(receiver, controller, REQUEST_ID, msg.sender, shares);\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-7540 claim\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC7575\n /// @notice DOES NOT support controller != msg.sender since shares are already transferred on requestRedeem\n function withdraw(uint256 assets, address receiver, address controller) public returns (uint256 shares) {\n _validateController(controller);\n shares = asyncRedeemManager.withdraw(this, assets, receiver, controller);\n emit Withdraw(msg.sender, receiver, controller, assets, shares);\n }\n\n /// @inheritdoc IERC7575\n /// @notice DOES NOT support controller != msg.sender since shares are already transferred on requestRedeem.\n /// When claiming redemption requests using redeem(), there can be some precision loss leading to dust.\n /// It is recommended to use withdraw() to claim redemption requests instead.\n function redeem(uint256 shares, address receiver, address controller) external returns (uint256 assets) {\n _validateController(controller);\n assets = asyncRedeemManager.redeem(this, shares, receiver, controller);\n emit Withdraw(msg.sender, receiver, controller, assets, shares);\n }\n\n //----------------------------------------------------------------------------------------------\n // Event emitters\n //----------------------------------------------------------------------------------------------\n\n function onRedeemRequest(address controller, address owner, uint256 shares) public virtual auth {\n emit RedeemRequest(controller, owner, REQUEST_ID, msg.sender, shares);\n }\n\n function onRedeemClaimable(address controller, uint256 assets, uint256 shares) public virtual auth {\n emit RedeemClaimable(controller, REQUEST_ID, assets, shares);\n }\n\n function onCancelRedeemClaimable(address controller, uint256 shares) public virtual auth {\n emit CancelRedeemClaimable(controller, REQUEST_ID, shares);\n }\n\n //----------------------------------------------------------------------------------------------\n // View methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC165\n function supportsInterface(bytes4 interfaceId) public pure virtual override(BaseVault, IERC165) returns (bool) {\n return super.supportsInterface(interfaceId) || interfaceId == type(IERC7540Redeem).interfaceId\n || interfaceId == type(IERC7887Redeem).interfaceId;\n }\n\n /// @inheritdoc IERC7575\n function maxWithdraw(address controller) public view returns (uint256 maxAssets) {\n maxAssets = asyncRedeemManager.maxWithdraw(this, controller);\n }\n\n /// @inheritdoc IERC7575\n function maxRedeem(address controller) public view returns (uint256 maxShares) {\n maxShares = asyncRedeemManager.maxRedeem(this, controller);\n }\n\n /// @dev Preview functions for ERC-7540 vaults revert\n function previewWithdraw(uint256) external pure returns (uint256) {\n revert();\n }\n\n /// @dev Preview functions for ERC-7540 vaults revert\n function previewRedeem(uint256) external pure returns (uint256) {\n revert();\n }\n}\n\nabstract contract BaseSyncDepositVault is BaseVault {\n ISyncDepositManager public syncDepositManager;\n\n constructor(ISyncDepositManager syncRequestManager_) {\n syncDepositManager = syncRequestManager_;\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-4626\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC7575\n function maxDeposit(address owner) public view returns (uint256 maxAssets) {\n maxAssets = syncDepositManager.maxDeposit(this, owner);\n }\n\n /// @inheritdoc IERC7575\n function previewDeposit(uint256 assets) external view override returns (uint256 shares) {\n shares = syncDepositManager.previewDeposit(this, msg.sender, assets);\n }\n\n /// @inheritdoc IERC7575\n function deposit(uint256 assets, address receiver) external returns (uint256 shares) {\n shares = syncDepositManager.deposit(this, assets, receiver, msg.sender);\n // NOTE: For security reasons, transfer must stay at end of call despite the fact that it logically should\n // happen before depositing in the manager\n SafeTransferLib.safeTransferFrom(asset, msg.sender, address(manager.poolEscrow(poolId)), assets);\n emit Deposit(receiver, msg.sender, assets, shares);\n }\n\n /// @inheritdoc IERC7575\n function maxMint(address owner) public view returns (uint256 maxShares) {\n maxShares = syncDepositManager.maxMint(this, owner);\n }\n\n /// @inheritdoc IERC7575\n function previewMint(uint256 shares) external view returns (uint256 assets) {\n assets = syncDepositManager.previewMint(this, msg.sender, shares);\n }\n\n /// @inheritdoc IERC7575\n function mint(uint256 shares, address receiver) public returns (uint256 assets) {\n assets = syncDepositManager.mint(this, shares, receiver, msg.sender);\n // NOTE: For security reasons, transfer must stay at end of call\n SafeTransferLib.safeTransferFrom(asset, msg.sender, address(manager.poolEscrow(poolId)), assets);\n emit Deposit(receiver, msg.sender, assets, shares);\n }\n\n /// @inheritdoc IERC165\n function supportsInterface(bytes4 interfaceId) public pure virtual override(BaseVault) returns (bool) {\n return super.supportsInterface(interfaceId);\n }\n}\n" + }, + "src/vaults/Escrow.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {IERC20} from \"src/misc/interfaces/IERC20.sol\";\nimport {IERC6909} from \"src/misc/interfaces/IERC6909.sol\";\nimport {SafeTransferLib} from \"src/misc/libraries/SafeTransferLib.sol\";\nimport {Recoverable} from \"src/misc/Recoverable.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {Holding, IPoolEscrow, IEscrow} from \"src/vaults/interfaces/IEscrow.sol\";\n\ncontract Escrow is Auth, IEscrow {\n constructor(address deployer) Auth(deployer) {}\n\n /// @inheritdoc IEscrow\n function authTransferTo(address asset, uint256 tokenId, address receiver, uint256 amount) public auth {\n if (tokenId == 0) {\n uint256 balance = IERC20(asset).balanceOf(address(this));\n require(balance >= amount, InsufficientBalance(asset, tokenId, amount, balance));\n\n SafeTransferLib.safeTransfer(asset, receiver, amount);\n } else {\n uint256 balance = IERC6909(asset).balanceOf(address(this), tokenId);\n require(balance >= amount, InsufficientBalance(asset, tokenId, amount, balance));\n\n IERC6909(asset).transfer(receiver, tokenId, amount);\n }\n\n emit AuthTransferTo(asset, tokenId, receiver, amount);\n }\n\n /// @inheritdoc IEscrow\n function authTransferTo(address asset, address receiver, uint256 amount) external auth {\n authTransferTo(asset, 0, receiver, amount);\n }\n}\n\n/// @title Escrow\n/// @notice Escrow contract that holds assets for a specific pool separated by share classes.\n/// Only wards can approve funds to be taken out.\ncontract PoolEscrow is Escrow, Recoverable, IPoolEscrow {\n /// @dev The underlying pool id\n PoolId public immutable poolId;\n\n mapping(ShareClassId scId => mapping(address asset => mapping(uint256 tokenId => Holding))) public holding;\n\n constructor(PoolId poolId_, address deployer) Escrow(deployer) {\n poolId = poolId_;\n }\n\n receive() external payable {}\n\n /// @inheritdoc IPoolEscrow\n function deposit(ShareClassId scId, address asset, uint256 tokenId, uint128 value) external auth {\n holding[scId][asset][tokenId].total += value;\n\n emit Deposit(asset, tokenId, poolId, scId, value);\n }\n\n /// @inheritdoc IPoolEscrow\n function withdraw(ShareClassId scId, address asset, uint256 tokenId, uint128 value) external auth {\n Holding storage holding_ = holding[scId][asset][tokenId];\n uint128 balance = holding_.total - holding_.reserved;\n require(balance >= value, InsufficientBalance(asset, tokenId, value, balance));\n\n holding_.total -= value;\n\n emit Withdraw(asset, tokenId, poolId, scId, value);\n }\n\n /// @inheritdoc IPoolEscrow\n function reserveIncrease(ShareClassId scId, address asset, uint256 tokenId, uint128 value) external auth {\n uint128 newValue = holding[scId][asset][tokenId].reserved + value;\n holding[scId][asset][tokenId].reserved = newValue;\n\n emit IncreaseReserve(asset, tokenId, poolId, scId, value, newValue);\n }\n\n /// @inheritdoc IPoolEscrow\n function reserveDecrease(ShareClassId scId, address asset, uint256 tokenId, uint128 value) external auth {\n uint128 prevValue = holding[scId][asset][tokenId].reserved;\n uint128 value_ = value;\n require(prevValue >= value_, InsufficientReservedAmount());\n\n uint128 newValue = prevValue - value_;\n holding[scId][asset][tokenId].reserved = newValue;\n\n emit DecreaseReserve(asset, tokenId, poolId, scId, value, newValue);\n }\n\n /// @inheritdoc IPoolEscrow\n function availableBalanceOf(ShareClassId scId, address asset, uint256 tokenId) public view returns (uint128) {\n Holding storage holding_ = holding[scId][asset][tokenId];\n if (holding_.total < holding_.reserved) return 0;\n return holding_.total - holding_.reserved;\n }\n}\n" + }, + "src/vaults/PoolManager.sol": { + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.28;\n\nimport {IERC20Metadata, IERC20Wrapper} from \"src/misc/interfaces/IERC20.sol\";\nimport {IERC6909MetadataExt} from \"src/misc/interfaces/IERC6909.sol\";\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {IAuth} from \"src/misc/interfaces/IAuth.sol\";\nimport {D18} from \"src/misc/types/D18.sol\";\nimport {Recoverable} from \"src/misc/Recoverable.sol\";\nimport {IERC165} from \"src/misc/interfaces/IERC7575.sol\";\nimport {ReentrancyProtection} from \"src/misc/ReentrancyProtection.sol\";\n\nimport {VaultUpdateKind, MessageLib, UpdateContractType} from \"src/common/libraries/MessageLib.sol\";\nimport {IGateway} from \"src/common/interfaces/IGateway.sol\";\nimport {IPoolManagerGatewayHandler} from \"src/common/interfaces/IGatewayHandlers.sol\";\nimport {IVaultMessageSender} from \"src/common/interfaces/IGatewaySenders.sol\";\nimport {newAssetId, AssetId} from \"src/common/types/AssetId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {PricingLib} from \"src/common/libraries/PricingLib.sol\";\n\nimport {IVaultFactory} from \"src/vaults/interfaces/factories/IVaultFactory.sol\";\nimport {IBaseVault, VaultKind} from \"src/vaults/interfaces/IBaseVaults.sol\";\nimport {IBaseRequestManager} from \"src/vaults/interfaces/investments/IBaseRequestManager.sol\";\nimport {ITokenFactory} from \"src/vaults/interfaces/factories/ITokenFactory.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\nimport {IPoolEscrowFactory} from \"src/vaults/interfaces/factories/IPoolEscrowFactory.sol\";\nimport {IHook} from \"src/common/interfaces/IHook.sol\";\nimport {IUpdateContract} from \"src/vaults/interfaces/IUpdateContract.sol\";\nimport {\n AssetIdKey,\n Pool,\n ShareClassDetails,\n Price,\n VaultDetails,\n IPoolManager\n} from \"src/vaults/interfaces/IPoolManager.sol\";\nimport {IAsyncRequestManager} from \"src/vaults/interfaces/investments/IAsyncRequestManager.sol\";\nimport {ISyncRequestManager} from \"src/vaults/interfaces/investments/ISyncRequestManager.sol\";\nimport {IPoolEscrow} from \"src/vaults/interfaces/IEscrow.sol\";\n\n/// @title Pool Manager\n/// @notice This contract manages which pools & share classes exist,\n/// as well as managing allowed pool currencies, and incoming and outgoing transfers.\ncontract PoolManager is\n Auth,\n Recoverable,\n ReentrancyProtection,\n IPoolManager,\n IUpdateContract,\n IPoolManagerGatewayHandler\n{\n using CastLib for *;\n using MessageLib for *;\n using BytesLib for bytes;\n using MathLib for uint256;\n\n uint8 internal constant MIN_DECIMALS = 2;\n uint8 internal constant MAX_DECIMALS = 18;\n\n IGateway public gateway;\n address public balanceSheet;\n ITokenFactory public tokenFactory;\n IVaultMessageSender public sender;\n IPoolEscrowFactory public poolEscrowFactory;\n IAsyncRequestManager public asyncRequestManager;\n ISyncRequestManager public syncRequestManager;\n\n uint64 internal _assetCounter;\n\n mapping(PoolId poolId => Pool) public pools;\n mapping(IVaultFactory factory => bool) public vaultFactory;\n\n mapping(IBaseVault => VaultDetails) internal _vaultDetails;\n mapping(AssetId assetId => AssetIdKey) internal _idToAsset;\n mapping(address asset => mapping(uint256 tokenId => AssetId assetId)) internal _assetToId;\n\n constructor(ITokenFactory tokenFactory_, address deployer) Auth(deployer) {\n tokenFactory = tokenFactory_;\n }\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IPoolManager\n function file(bytes32 what, address data) external auth {\n if (what == \"sender\") sender = IVaultMessageSender(data);\n else if (what == \"tokenFactory\") tokenFactory = ITokenFactory(data);\n else if (what == \"gateway\") gateway = IGateway(data);\n else if (what == \"balanceSheet\") balanceSheet = data;\n else if (what == \"poolEscrowFactory\") poolEscrowFactory = IPoolEscrowFactory(data);\n else if (what == \"asyncRequestManager\") asyncRequestManager = IAsyncRequestManager(data);\n else if (what == \"syncRequestManager\") syncRequestManager = ISyncRequestManager(data);\n else revert FileUnrecognizedParam();\n emit File(what, data);\n }\n\n /// @inheritdoc IPoolManager\n function file(bytes32 what, address factory, bool status) external auth {\n if (what == \"vaultFactory\") {\n vaultFactory[IVaultFactory(factory)] = status;\n } else {\n revert FileUnrecognizedParam();\n }\n emit File(what, factory, status);\n }\n\n //----------------------------------------------------------------------------------------------\n // Outgoing methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IPoolManager\n function transferShares(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bytes32 receiver, uint128 amount)\n external\n payable\n protected\n {\n IShareToken share = IShareToken(shareToken(poolId, scId));\n require(centrifugeId != sender.localCentrifugeId(), LocalTransferNotAllowed());\n require(\n share.checkTransferRestriction(msg.sender, address(uint160(centrifugeId)), amount),\n CrossChainTransferNotAllowed()\n );\n\n gateway.payTransaction{value: msg.value}(msg.sender);\n\n share.authTransferFrom(msg.sender, msg.sender, address(this), amount);\n share.burn(address(this), amount);\n\n emit TransferShares(centrifugeId, poolId, scId, msg.sender, receiver, amount);\n sender.sendTransferShares(centrifugeId, poolId, scId, receiver, amount);\n }\n\n // @inheritdoc IPoolManager\n function registerAsset(uint16 centrifugeId, address asset, uint256 tokenId)\n external\n payable\n protected\n returns (AssetId assetId)\n {\n string memory name;\n string memory symbol;\n uint8 decimals;\n\n decimals = _safeGetAssetDecimals(asset, tokenId);\n require(decimals >= MIN_DECIMALS, TooFewDecimals());\n require(decimals <= MAX_DECIMALS, TooManyDecimals());\n\n gateway.payTransaction{value: msg.value}(msg.sender);\n\n if (tokenId == 0) {\n IERC20Metadata meta = IERC20Metadata(asset);\n name = meta.name();\n symbol = meta.symbol();\n } else {\n IERC6909MetadataExt meta = IERC6909MetadataExt(asset);\n name = meta.name(tokenId);\n symbol = meta.symbol(tokenId);\n }\n\n assetId = _assetToId[asset][tokenId];\n if (assetId.raw() == 0) {\n _assetCounter++;\n assetId = newAssetId(sender.localCentrifugeId(), _assetCounter);\n\n _idToAsset[assetId] = AssetIdKey(asset, tokenId);\n _assetToId[asset][tokenId] = assetId;\n\n emit RegisterAsset(assetId, asset, tokenId, name, symbol, decimals);\n }\n\n sender.sendRegisterAsset(centrifugeId, assetId, decimals);\n }\n\n //----------------------------------------------------------------------------------------------\n // Incoming\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IPoolManagerGatewayHandler\n function addPool(PoolId poolId) public auth {\n Pool storage pool = pools[poolId];\n require(pool.createdAt == 0, PoolAlreadyAdded());\n pool.createdAt = block.timestamp;\n\n IPoolEscrow escrow = poolEscrowFactory.newEscrow(poolId);\n gateway.setRefundAddress(PoolId.wrap(poolId.raw()), escrow);\n\n emit AddPool(poolId);\n }\n\n /// @inheritdoc IPoolManagerGatewayHandler\n function addShareClass(\n PoolId poolId,\n ShareClassId scId,\n string memory name,\n string memory symbol,\n uint8 decimals,\n bytes32 salt,\n address hook\n ) public auth {\n require(decimals >= MIN_DECIMALS, TooFewDecimals());\n require(decimals <= MAX_DECIMALS, TooManyDecimals());\n require(isPoolActive(poolId), InvalidPool());\n\n Pool storage pool = pools[poolId];\n require(address(pool.shareClasses[scId].shareToken) == address(0), ShareClassAlreadyRegistered());\n\n // Hook can be address zero if the share token is fully permissionless and has no custom logic\n require(hook == address(0) || _isValidHook(hook), InvalidHook());\n\n address[] memory tokenWards = new address[](2);\n tokenWards[0] = address(this);\n // BalanceSheet needs this in order to mint shares\n tokenWards[1] = balanceSheet;\n\n IShareToken shareToken_ = tokenFactory.newToken(name, symbol, decimals, salt, tokenWards);\n\n if (hook != address(0)) {\n shareToken_.file(\"hook\", hook);\n }\n\n pool.shareClasses[scId].shareToken = shareToken_;\n\n emit AddShareClass(poolId, scId, shareToken_);\n }\n\n /// @inheritdoc IPoolManagerGatewayHandler\n function updateShareMetadata(PoolId poolId, ShareClassId scId, string memory name, string memory symbol)\n public\n auth\n {\n IShareToken shareToken_ = shareToken(poolId, scId);\n\n require(\n keccak256(bytes(shareToken_.name())) != keccak256(bytes(name))\n || keccak256(bytes(shareToken_.symbol())) != keccak256(bytes(symbol)),\n OldMetadata()\n );\n\n shareToken_.file(\"name\", name);\n shareToken_.file(\"symbol\", symbol);\n }\n\n /// @inheritdoc IPoolManagerGatewayHandler\n function updatePricePoolPerShare(PoolId poolId, ShareClassId scId, uint128 price, uint64 computedAt) public auth {\n ShareClassDetails storage shareClass = _shareClass(poolId, scId);\n\n require(computedAt >= shareClass.pricePoolPerShare.computedAt, CannotSetOlderPrice());\n\n shareClass.pricePoolPerShare = Price(price, computedAt, shareClass.pricePoolPerShare.maxAge);\n emit PriceUpdate(poolId, scId, price, computedAt);\n }\n\n /// @inheritdoc IPoolManagerGatewayHandler\n function updatePricePoolPerAsset(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n uint128 poolPerAsset_,\n uint64 computedAt\n ) public auth {\n ShareClassDetails storage shareClass = _shareClass(poolId, scId);\n\n (address asset, uint256 tokenId) = idToAsset(assetId);\n Price storage poolPerAsset = shareClass.pricePoolPerAsset[asset][tokenId];\n require(computedAt >= poolPerAsset.computedAt, CannotSetOlderPrice());\n\n // Disable expiration of the price\n if (poolPerAsset.computedAt == 0) {\n poolPerAsset.maxAge = type(uint64).max;\n }\n poolPerAsset.price = poolPerAsset_;\n poolPerAsset.computedAt = computedAt;\n\n emit PriceUpdate(poolId, scId, asset, tokenId, poolPerAsset_, computedAt);\n }\n\n /// @inheritdoc IPoolManagerGatewayHandler\n function updateRestriction(PoolId poolId, ShareClassId scId, bytes memory update_) public auth {\n IShareToken shareToken_ = shareToken(poolId, scId);\n address hook = shareToken_.hook();\n require(hook != address(0), InvalidHook());\n IHook(hook).updateRestriction(address(shareToken_), update_);\n }\n\n /// @inheritdoc IPoolManagerGatewayHandler\n function updateContract(PoolId poolId, ShareClassId scId, address target, bytes memory update_) public auth {\n if (target == address(this)) {\n update(poolId, scId, update_);\n } else {\n IUpdateContract(target).update(poolId, scId, update_);\n }\n\n emit UpdateContract(poolId, scId, target, update_);\n }\n\n /// @inheritdoc IPoolManagerGatewayHandler\n function updateShareHook(PoolId poolId, ShareClassId scId, address hook) public auth {\n IShareToken shareToken_ = shareToken(poolId, scId);\n require(hook != shareToken_.hook(), OldHook());\n shareToken_.file(\"hook\", hook);\n }\n\n /// @inheritdoc IPoolManagerGatewayHandler\n function handleTransferShares(PoolId poolId, ShareClassId scId, address destinationAddress, uint128 amount)\n public\n auth\n {\n IShareToken shareToken_ = shareToken(poolId, scId);\n\n shareToken_.mint(destinationAddress, amount);\n }\n\n /// @inheritdoc IUpdateContract\n /// @notice The pool manager either deploys the vault if a factory address is provided\n /// or it simply links/unlinks the vault.\n function update(PoolId poolId, ShareClassId scId, bytes memory payload) public auth {\n uint8 kind = uint8(MessageLib.updateContractType(payload));\n\n if (kind == uint8(UpdateContractType.VaultUpdate)) {\n MessageLib.UpdateContractVaultUpdate memory m = MessageLib.deserializeUpdateContractVaultUpdate(payload);\n\n if (m.kind == uint8(VaultUpdateKind.DeployAndLink)) {\n IVaultFactory factory = IVaultFactory(m.vaultOrFactory.toAddress());\n\n IBaseVault vault = deployVault(poolId, scId, AssetId.wrap(m.assetId), factory);\n linkVault(poolId, scId, AssetId.wrap(m.assetId), vault);\n } else {\n IBaseVault vault = IBaseVault(m.vaultOrFactory.toAddress());\n\n // Needed as safeguard against non-validated vaults\n // I.e. we only accept vaults that have been deployed by the pool manager\n require(_vaultDetails[vault].asset != address(0), UnknownVault());\n\n if (m.kind == uint8(VaultUpdateKind.Link)) {\n linkVault(poolId, scId, AssetId.wrap(m.assetId), vault);\n } else if (m.kind == uint8(VaultUpdateKind.Unlink)) {\n unlinkVault(poolId, scId, AssetId.wrap(m.assetId), vault);\n } else {\n revert MalformedVaultUpdateMessage();\n }\n }\n } else if (kind == uint8(UpdateContractType.MaxAssetPriceAge)) {\n MessageLib.UpdateContractMaxAssetPriceAge memory m =\n MessageLib.deserializeUpdateContractMaxAssetPriceAge(payload);\n\n ShareClassDetails storage shareClass = _shareClass(poolId, scId);\n require(m.assetId != 0, UnknownAsset());\n\n (address asset, uint256 tokenId) = idToAsset(AssetId.wrap(m.assetId));\n shareClass.pricePoolPerAsset[asset][tokenId].maxAge = m.maxPriceAge;\n emit UpdateMaxAssetPriceAge(poolId, scId, asset, tokenId, m.maxPriceAge);\n } else if (kind == uint8(UpdateContractType.MaxSharePriceAge)) {\n MessageLib.UpdateContractMaxSharePriceAge memory m =\n MessageLib.deserializeUpdateContractMaxSharePriceAge(payload);\n\n ShareClassDetails storage shareClass = _shareClass(poolId, scId);\n\n shareClass.pricePoolPerShare.maxAge = m.maxPriceAge;\n emit UpdateMaxSharePriceAge(poolId, scId, m.maxPriceAge);\n } else {\n revert UnknownUpdateContractType();\n }\n }\n\n /// @inheritdoc IPoolManager\n function linkVault(PoolId poolId, ShareClassId scId, AssetId assetId, IBaseVault vault) public auth {\n _shareClass(poolId, scId);\n\n AssetIdKey memory assetIdKey = _idToAsset[assetId];\n\n IBaseRequestManager manager = vault.manager();\n manager.addVault(poolId, scId, vault, assetIdKey.asset, assetId);\n\n _vaultDetails[vault].isLinked = true;\n\n emit LinkVault(poolId, scId, assetIdKey.asset, assetIdKey.tokenId, vault);\n }\n\n /// @inheritdoc IPoolManager\n function unlinkVault(PoolId poolId, ShareClassId scId, AssetId assetId, IBaseVault vault) public auth {\n _shareClass(poolId, scId);\n\n AssetIdKey memory assetIdKey = _idToAsset[assetId];\n\n IBaseRequestManager manager = vault.manager();\n manager.removeVault(poolId, scId, vault, assetIdKey.asset, assetId);\n\n _vaultDetails[vault].isLinked = false;\n\n emit UnlinkVault(poolId, scId, assetIdKey.asset, assetIdKey.tokenId, vault);\n }\n\n /// @inheritdoc IPoolManager\n function deployVault(PoolId poolId, ShareClassId scId, AssetId assetId, IVaultFactory factory)\n public\n auth\n returns (IBaseVault)\n {\n ShareClassDetails storage shareClass = _shareClass(poolId, scId);\n require(vaultFactory[factory], InvalidFactory());\n\n // Rely investment manager on vault so it can mint tokens\n address[] memory vaultWards = new address[](0);\n\n // Deploy vault\n AssetIdKey memory assetIdKey = _idToAsset[assetId];\n IBaseVault vault = IVaultFactory(factory).newVault(\n poolId, scId, assetIdKey.asset, assetIdKey.tokenId, shareClass.shareToken, vaultWards\n );\n\n // Check whether asset is an ERC20 token wrapper\n (bool success, bytes memory data) =\n assetIdKey.asset.staticcall(abi.encodeWithSelector(IERC20Wrapper.underlying.selector));\n // On success, the returned 20 byte address is padded to 32 bytes\n bool isWrappedERC20 = success && data.length == 32;\n _vaultDetails[vault] = VaultDetails(assetId, assetIdKey.asset, assetIdKey.tokenId, isWrappedERC20, false);\n\n // NOTE - Reverting the manager approvals is not easy. We SHOULD do that if we phase-out a manager\n VaultKind vaultKind = _relyShareToken(vault, shareClass.shareToken);\n\n emit DeployVault(poolId, scId, assetIdKey.asset, assetIdKey.tokenId, factory, vault, vaultKind);\n return vault;\n }\n\n //----------------------------------------------------------------------------------------------\n // View methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IPoolManager\n function isPoolActive(PoolId poolId) public view returns (bool) {\n return pools[poolId].createdAt > 0;\n }\n\n /// @inheritdoc IPoolManager\n function shareToken(PoolId poolId, ShareClassId scId) public view returns (IShareToken) {\n ShareClassDetails storage shareClass = pools[poolId].shareClasses[scId];\n require(address(shareClass.shareToken) != address(0), UnknownToken());\n return shareClass.shareToken;\n }\n\n /// @inheritdoc IPoolManager\n function vaultDetails(IBaseVault vault) public view returns (VaultDetails memory details) {\n details = _vaultDetails[vault];\n require(details.asset != address(0), UnknownVault());\n }\n\n /// @inheritdoc IPoolManager\n function isLinked(PoolId, /* poolId */ ShareClassId, /* scId */ address, /* asset */ IBaseVault vault)\n public\n view\n returns (bool)\n {\n return _vaultDetails[vault].isLinked;\n }\n\n /// @inheritdoc IPoolManager\n function idToAsset(AssetId assetId) public view returns (address asset, uint256 tokenId) {\n AssetIdKey memory assetIdKey = _idToAsset[assetId];\n require(assetIdKey.asset != address(0), UnknownAsset());\n return (assetIdKey.asset, assetIdKey.tokenId);\n }\n\n /// @inheritdoc IPoolManager\n function assetToId(address asset, uint256 tokenId) public view returns (AssetId assetId) {\n assetId = _assetToId[asset][tokenId];\n require(assetId.raw() != 0, UnknownAsset());\n }\n\n /// @inheritdoc IPoolManager\n function priceAssetPerShare(PoolId poolId, ShareClassId scId, AssetId assetId, bool checkValidity)\n public\n view\n returns (D18 price)\n {\n (Price memory poolPerAsset, Price memory poolPerShare) = _pricesPoolPer(poolId, scId, assetId, checkValidity);\n\n price = PricingLib.priceAssetPerShare(poolPerShare.asPrice(), poolPerAsset.asPrice());\n }\n\n /// @inheritdoc IPoolManager\n function pricePoolPerShare(PoolId poolId, ShareClassId scId, bool checkValidity) public view returns (D18 price) {\n ShareClassDetails storage shareClass = _shareClass(poolId, scId);\n\n if (checkValidity) {\n require(shareClass.pricePoolPerShare.isValid(), InvalidPrice());\n }\n\n price = shareClass.pricePoolPerShare.asPrice();\n }\n\n /// @inheritdoc IPoolManager\n function pricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId, bool checkValidity)\n public\n view\n returns (D18 price)\n {\n (Price memory poolPerAsset,) = _pricesPoolPer(poolId, scId, assetId, false);\n\n if (checkValidity) {\n require(poolPerAsset.isValid(), InvalidPrice());\n }\n\n price = poolPerAsset.asPrice();\n }\n\n /// @inheritdoc IPoolManager\n function pricesPoolPer(PoolId poolId, ShareClassId scId, AssetId assetId, bool checkValidity)\n public\n view\n returns (D18 pricePoolPerAsset_, D18 pricePoolPerShare_)\n {\n (Price memory poolPerAsset, Price memory poolPerShare) = _pricesPoolPer(poolId, scId, assetId, checkValidity);\n return (poolPerAsset.asPrice(), poolPerShare.asPrice());\n }\n\n /// @inheritdoc IPoolManager\n function markersPricePoolPerShare(PoolId poolId, ShareClassId scId)\n external\n view\n returns (uint64 computedAt, uint64 maxAge, uint64 validUntil)\n {\n ShareClassDetails storage shareClass = _shareClass(poolId, scId);\n computedAt = shareClass.pricePoolPerShare.computedAt;\n maxAge = shareClass.pricePoolPerShare.maxAge;\n validUntil = shareClass.pricePoolPerShare.validUntil();\n }\n\n /// @inheritdoc IPoolManager\n function markersPricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId)\n external\n view\n returns (uint64 computedAt, uint64 maxAge, uint64 validUntil)\n {\n (Price memory poolPerAsset,) = _pricesPoolPer(poolId, scId, assetId, false);\n computedAt = poolPerAsset.computedAt;\n maxAge = poolPerAsset.maxAge;\n validUntil = poolPerAsset.validUntil();\n }\n\n //----------------------------------------------------------------------------------------------\n // Internal methods\n //----------------------------------------------------------------------------------------------\n\n function _pricesPoolPer(PoolId poolId, ShareClassId scId, AssetId assetId, bool checkValidity)\n internal\n view\n returns (Price memory poolPerAsset, Price memory poolPerShare)\n {\n ShareClassDetails storage shareClass = _shareClass(poolId, scId);\n\n (address asset, uint256 tokenId) = idToAsset(assetId);\n poolPerAsset = shareClass.pricePoolPerAsset[asset][tokenId];\n poolPerShare = shareClass.pricePoolPerShare;\n\n if (checkValidity) {\n require(poolPerAsset.isValid(), InvalidPrice());\n require(poolPerShare.isValid(), InvalidPrice());\n }\n }\n\n /// @dev Sets up approval permissions for pool, i.e. the pool escrow, the base vault manager and potentially a\n /// secondary manager (in case of partially sync vault)\n function _relyShareToken(IBaseVault vault, IShareToken shareToken_) internal returns (VaultKind) {\n IBaseRequestManager manager = vault.manager();\n IAuth(address(shareToken_)).rely(address(manager));\n\n // For sync deposit & async redeem vault, also repeat above for async manager\n VaultKind vaultKind = vault.vaultKind();\n if (vaultKind == VaultKind.SyncDepositAsyncRedeem) {\n IAuth(address(shareToken_)).rely(address(asyncRequestManager));\n }\n\n return vaultKind;\n }\n\n function _safeGetAssetDecimals(address asset, uint256 tokenId) private view returns (uint8) {\n bytes memory callData;\n\n if (tokenId == 0) {\n callData = abi.encodeWithSignature(\"decimals()\");\n } else {\n callData = abi.encodeWithSignature(\"decimals(uint256)\", tokenId);\n }\n\n (bool success, bytes memory data) = asset.staticcall(callData);\n require(success && data.length >= 32, AssetMissingDecimals());\n\n return abi.decode(data, (uint8));\n }\n\n function _isValidHook(address hook) internal view returns (bool) {\n (bool success, bytes memory data) =\n hook.staticcall(abi.encodeWithSelector(IERC165.supportsInterface.selector, type(IHook).interfaceId));\n\n return success && data.length == 32 && abi.decode(data, (bool));\n }\n\n function _shareClass(PoolId poolId, ShareClassId scId)\n internal\n view\n returns (ShareClassDetails storage shareClass)\n {\n shareClass = pools[poolId].shareClasses[scId];\n require(address(shareClass.shareToken) != address(0), ShareTokenDoesNotExist());\n }\n}\n" + }, + "src/vaults/SyncDepositVault.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IERC165} from \"src/misc/interfaces/IERC7575.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nimport {BaseVault, BaseAsyncRedeemVault, BaseSyncDepositVault} from \"src/vaults/BaseVaults.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\nimport {IAsyncRedeemManager} from \"src/vaults/interfaces/investments/IAsyncRedeemManager.sol\";\nimport {ISyncDepositManager} from \"src/vaults/interfaces/investments/ISyncDepositManager.sol\";\nimport {IBaseRequestManager} from \"src/vaults/interfaces/investments/IBaseRequestManager.sol\";\nimport {VaultKind} from \"src/vaults/interfaces/IBaseVaults.sol\";\n\n/// @title SyncDepositVault\n/// @notice Partially (a)synchronous Tokenized Vault implementation with synchronous deposits\n/// and asynchronous redemptions following ERC-7540.\n///\n/// @dev Each vault issues shares of Centrifuge share class tokens as restricted ERC-20 tokens\n/// against asset deposits based on the current share price.\ncontract SyncDepositVault is BaseSyncDepositVault, BaseAsyncRedeemVault {\n constructor(\n PoolId poolId_,\n ShareClassId scId_,\n address asset_,\n IShareToken token_,\n address root_,\n ISyncDepositManager syncDepositManager_,\n IAsyncRedeemManager asyncRedeemManager_\n )\n BaseVault(poolId_, scId_, asset_, token_, root_, syncDepositManager_)\n BaseSyncDepositVault(syncDepositManager_)\n BaseAsyncRedeemVault(asyncRedeemManager_)\n {}\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n function file(bytes32 what, address data) external override(BaseAsyncRedeemVault, BaseVault) auth {\n if (what == \"manager\") manager = IBaseRequestManager(data);\n else if (what == \"asyncRedeemManager\") asyncRedeemManager = IAsyncRedeemManager(data);\n else if (what == \"syncDepositManager\") syncDepositManager = ISyncDepositManager(data);\n else revert FileUnrecognizedParam();\n emit File(what, data);\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-165\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC165\n function supportsInterface(bytes4 interfaceId)\n public\n pure\n override(BaseAsyncRedeemVault, BaseSyncDepositVault)\n returns (bool)\n {\n return super.supportsInterface(interfaceId);\n }\n\n //----------------------------------------------------------------------------------------------\n // IBaseVault view\n //----------------------------------------------------------------------------------------------\n\n function vaultKind() public pure returns (VaultKind vaultKind_) {\n return VaultKind.SyncDepositAsyncRedeem;\n }\n}\n" + }, + "src/vaults/SyncRequestManager.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IERC165} from \"forge-std/interfaces/IERC165.sol\";\nimport {IERC7540Redeem} from \"src/misc/interfaces/IERC7540.sol\";\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {IAuth} from \"src/misc/interfaces/IAuth.sol\";\nimport {d18, D18} from \"src/misc/types/D18.sol\";\n\nimport {MessageLib, UpdateContractType} from \"src/common/libraries/MessageLib.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {PricingLib} from \"src/common/libraries/PricingLib.sol\";\n\nimport {BaseRequestManager} from \"src/vaults/BaseRequestManager.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\nimport {IAsyncRedeemVault, IBaseVault, VaultKind} from \"src/vaults/interfaces/IBaseVaults.sol\";\nimport {IPoolManager, VaultDetails} from \"src/vaults/interfaces/IPoolManager.sol\";\nimport {IBalanceSheet} from \"src/vaults/interfaces/IBalanceSheet.sol\";\nimport {IBaseRequestManager} from \"src/vaults/interfaces/investments/IBaseRequestManager.sol\";\nimport {\n ISyncRequestManager,\n Prices,\n ISyncDepositValuation\n} from \"src/vaults/interfaces/investments/ISyncRequestManager.sol\";\nimport {IDepositManager} from \"src/vaults/interfaces/investments/IDepositManager.sol\";\nimport {ISyncDepositManager} from \"src/vaults/interfaces/investments/ISyncDepositManager.sol\";\nimport {IUpdateContract} from \"src/vaults/interfaces/IUpdateContract.sol\";\nimport {IEscrow} from \"src/vaults/interfaces/IEscrow.sol\";\nimport {IPoolEscrowProvider} from \"src/vaults/interfaces/factories/IPoolEscrowFactory.sol\";\nimport {IAsyncRedeemManager} from \"src/vaults/interfaces/investments/IAsyncRedeemManager.sol\";\n\n/// @title Sync Investment Manager\n/// @notice This is the main contract vaults interact with for\n/// both incoming and outgoing investment transactions.\ncontract SyncRequestManager is BaseRequestManager, ISyncRequestManager {\n using BytesLib for bytes;\n using MathLib for *;\n using CastLib for *;\n using MessageLib for *;\n\n IBalanceSheet public balanceSheet;\n\n mapping(PoolId => mapping(ShareClassId scId => ISyncDepositValuation)) public valuation;\n mapping(PoolId => mapping(ShareClassId scId => mapping(address asset => mapping(uint256 tokenId => uint128))))\n public maxReserve;\n\n constructor(IEscrow globalEscrow_, address root_, address deployer)\n BaseRequestManager(globalEscrow_, root_, deployer)\n {}\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IBaseRequestManager\n function file(bytes32 what, address data) external override(IBaseRequestManager, BaseRequestManager) auth {\n if (what == \"poolManager\") poolManager = IPoolManager(data);\n else if (what == \"balanceSheet\") balanceSheet = IBalanceSheet(data);\n else if (what == \"poolEscrowProvider\") poolEscrowProvider = IPoolEscrowProvider(data);\n else revert FileUnrecognizedParam();\n emit File(what, data);\n }\n\n /// @inheritdoc IUpdateContract\n function update(PoolId poolId, ShareClassId scId, bytes memory payload) external auth {\n uint8 kind = uint8(MessageLib.updateContractType(payload));\n\n if (kind == uint8(UpdateContractType.Valuation)) {\n MessageLib.UpdateContractValuation memory m = MessageLib.deserializeUpdateContractValuation(payload);\n\n require(address(poolManager.shareToken(poolId, scId)) != address(0), ShareTokenDoesNotExist());\n\n setValuation(poolId, scId, m.valuation.toAddress());\n } else if (kind == uint8(UpdateContractType.SyncDepositMaxReserve)) {\n MessageLib.UpdateContractSyncDepositMaxReserve memory m =\n MessageLib.deserializeUpdateContractSyncDepositMaxReserve(payload);\n\n require(address(poolManager.shareToken(poolId, scId)) != address(0), ShareTokenDoesNotExist());\n (address asset, uint256 tokenId) = poolManager.idToAsset(AssetId.wrap(m.assetId));\n\n setMaxReserve(poolId, scId, asset, tokenId, m.maxReserve);\n } else {\n revert UnknownUpdateContractType();\n }\n }\n\n /// @inheritdoc IBaseRequestManager\n function addVault(PoolId poolId, ShareClassId scId, IBaseVault vault_, address asset_, AssetId assetId)\n public\n override(BaseRequestManager, IBaseRequestManager)\n auth\n {\n super.addVault(poolId, scId, vault_, asset_, assetId);\n\n (, uint256 tokenId) = poolManager.idToAsset(assetId);\n setMaxReserve(poolId, scId, asset_, tokenId, type(uint128).max);\n\n VaultKind vaultKind_ = vault_.vaultKind();\n if (vaultKind_ == VaultKind.SyncDepositAsyncRedeem) {\n IAsyncRedeemManager asyncRequestManager = IAsyncRedeemVault(address(vault_)).asyncRedeemManager();\n require(address(asyncRequestManager) != address(0), SecondaryManagerDoesNotExist());\n asyncRequestManager.addVault(poolId, scId, vault_, asset_, assetId);\n }\n }\n\n /// @inheritdoc IBaseRequestManager\n function removeVault(PoolId poolId, ShareClassId scId, IBaseVault vault_, address asset_, AssetId assetId)\n public\n override(BaseRequestManager, IBaseRequestManager)\n auth\n {\n super.removeVault(poolId, scId, vault_, asset_, assetId);\n\n (, uint256 tokenId) = poolManager.idToAsset(assetId);\n delete maxReserve[poolId][scId][asset_][tokenId];\n\n VaultKind vaultKind_ = vault_.vaultKind();\n if (vaultKind_ == VaultKind.SyncDepositAsyncRedeem) {\n IAsyncRedeemManager asyncRequestManager = IAsyncRedeemVault(address(vault_)).asyncRedeemManager();\n require(address(asyncRequestManager) != address(0), SecondaryManagerDoesNotExist());\n asyncRequestManager.removeVault(poolId, scId, vault_, asset_, assetId);\n }\n }\n\n /// @inheritdoc ISyncRequestManager\n function setValuation(PoolId poolId, ShareClassId scId, address valuation_) public auth {\n valuation[poolId][scId] = ISyncDepositValuation(valuation_);\n\n emit SetValuation(poolId, scId, address(valuation_));\n }\n\n /// @inheritdoc ISyncRequestManager\n function setMaxReserve(PoolId poolId, ShareClassId scId, address asset, uint256 tokenId, uint128 maxReserve_)\n public\n auth\n {\n maxReserve[poolId][scId][asset][tokenId] = maxReserve_;\n\n emit SetMaxReserve(poolId, scId, asset, tokenId, maxReserve_);\n }\n\n //----------------------------------------------------------------------------------------------\n // Deposit handlers\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IDepositManager\n function mint(IBaseVault vault_, uint256 shares, address receiver, address owner)\n external\n auth\n returns (uint256 assets)\n {\n require(maxMint(vault_, owner) >= shares, ExceedsMaxMint());\n assets = previewMint(vault_, owner, shares);\n\n _issueShares(vault_, shares.toUint128(), receiver, owner, assets.toUint128());\n }\n\n /// @inheritdoc IDepositManager\n function deposit(IBaseVault vault_, uint256 assets, address receiver, address owner)\n external\n auth\n returns (uint256 shares)\n {\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n require(poolManager.isLinked(vault_.poolId(), vault_.scId(), vaultDetails.asset, vault_), AssetNotAllowed());\n\n require(maxDeposit(vault_, owner) >= assets, ExceedsMaxDeposit());\n shares = previewDeposit(vault_, owner, assets);\n\n _issueShares(vault_, shares.toUint128(), receiver, owner, assets.toUint128());\n }\n\n //----------------------------------------------------------------------------------------------\n // View methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc ISyncDepositManager\n function previewMint(IBaseVault vault_, address, /* sender */ uint256 shares)\n public\n view\n returns (uint256 assets)\n {\n return _shareToAssetAmount(vault_, shares, MathLib.Rounding.Up);\n }\n\n /// @inheritdoc ISyncDepositManager\n function previewDeposit(IBaseVault vault_, address, /* sender */ uint256 assets)\n public\n view\n returns (uint256 shares)\n {\n return convertToShares(vault_, assets);\n }\n\n /// @inheritdoc IDepositManager\n function maxMint(IBaseVault vault_, address /* owner */ ) public view returns (uint256) {\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n uint128 maxAssets = _maxDeposit(vault_.poolId(), vault_.scId(), vaultDetails.asset, vaultDetails.tokenId);\n return convertToShares(vault_, maxAssets);\n }\n\n /// @inheritdoc IDepositManager\n function maxDeposit(IBaseVault vault_, address /* owner */ ) public view returns (uint256) {\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n return _maxDeposit(vault_.poolId(), vault_.scId(), vaultDetails.asset, vaultDetails.tokenId);\n }\n\n /// @inheritdoc IBaseRequestManager\n function convertToShares(IBaseVault vault_, uint256 assets)\n public\n view\n override(IBaseRequestManager, BaseRequestManager)\n returns (uint256 shares)\n {\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n Prices memory prices_ = prices(vault_.poolId(), vault_.scId(), vaultDetails.assetId);\n\n return super._assetToShareAmount(\n vault_, vaultDetails, assets, prices_.poolPerAsset, prices_.poolPerShare, MathLib.Rounding.Down\n );\n }\n\n /// @inheritdoc IBaseRequestManager\n function convertToAssets(IBaseVault vault_, uint256 shares)\n public\n view\n override(IBaseRequestManager, BaseRequestManager)\n returns (uint256 assets)\n {\n return _shareToAssetAmount(vault_, shares, MathLib.Rounding.Down);\n }\n\n /// @inheritdoc ISyncDepositValuation\n function pricePoolPerShare(PoolId poolId, ShareClassId scId) public view returns (D18 price) {\n ISyncDepositValuation valuation_ = valuation[poolId][scId];\n\n if (address(valuation_) == address(0)) {\n price = poolManager.pricePoolPerShare(poolId, scId, true);\n } else {\n price = valuation_.pricePoolPerShare(poolId, scId);\n }\n }\n\n /// @inheritdoc ISyncRequestManager\n function prices(PoolId poolId, ShareClassId scId, AssetId assetId) public view returns (Prices memory priceData) {\n priceData.poolPerShare = pricePoolPerShare(poolId, scId);\n priceData.poolPerAsset = poolManager.pricePoolPerAsset(poolId, scId, assetId, true);\n priceData.assetPerShare = PricingLib.priceAssetPerShare(priceData.poolPerShare, priceData.poolPerAsset);\n }\n\n //----------------------------------------------------------------------------------------------\n // Internal\n //----------------------------------------------------------------------------------------------\n\n /// @dev Issues shares to the receiver and instruct the balance sheet\n // to react on the issuance and the updated holding.\n function _issueShares(IBaseVault vault_, uint128 shares, address receiver, address, /* owner */ uint128 assets)\n internal\n {\n PoolId poolId = vault_.poolId();\n ShareClassId scId = vault_.scId();\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n\n balanceSheet.overridePricePoolPerShare(poolId, scId, prices(poolId, scId, vaultDetails.assetId).poolPerShare);\n balanceSheet.issue(poolId, scId, receiver, shares);\n\n // Note deposit into the pool escrow, to make assets available for managers of the balance sheet\n // ERC-20 transfer is handled by the vault to the pool escrow afterwards\n balanceSheet.noteDeposit(poolId, scId, vaultDetails.asset, vaultDetails.tokenId, receiver, assets);\n }\n\n function _maxDeposit(PoolId poolId, ShareClassId scId, address asset, uint256 tokenId)\n internal\n view\n returns (uint128 maxDeposit_)\n {\n uint128 availableBalance = poolEscrowProvider.escrow(poolId).availableBalanceOf(scId, asset, tokenId);\n uint128 maxReserve_ = maxReserve[poolId][scId][asset][tokenId];\n\n if (maxReserve_ < availableBalance) {\n maxDeposit_ = 0;\n } else {\n maxDeposit_ = maxReserve_ - availableBalance;\n }\n }\n\n function _shareToAssetAmount(IBaseVault vault_, uint256 assets, MathLib.Rounding rounding)\n internal\n view\n returns (uint256 shares)\n {\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n Prices memory prices_ = prices(vault_.poolId(), vault_.scId(), vaultDetails.assetId);\n return super._shareToAssetAmount(\n vault_, vaultDetails, assets, prices_.poolPerAsset, prices_.poolPerShare, rounding\n );\n }\n}\n" + }, + "src/vaults/VaultRouter.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {Multicall, IMulticall} from \"src/misc/Multicall.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {SafeTransferLib} from \"src/misc/libraries/SafeTransferLib.sol\";\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {IERC20, IERC20Permit, IERC20Wrapper} from \"src/misc/interfaces/IERC20.sol\";\nimport {IERC7540Deposit} from \"src/misc/interfaces/IERC7540.sol\";\nimport {Recoverable} from \"src/misc/Recoverable.sol\";\n\nimport {IGateway} from \"src/common/interfaces/IGateway.sol\";\nimport {IMessageDispatcher} from \"src/common/interfaces/IMessageDispatcher.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nimport {IAsyncVault, IBaseVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\nimport {IVaultRouter} from \"src/vaults/interfaces/IVaultRouter.sol\";\nimport {IPoolManager, VaultDetails} from \"src/vaults/interfaces/IPoolManager.sol\";\nimport {IEscrow} from \"src/vaults/interfaces/IEscrow.sol\";\nimport {BaseSyncDepositVault} from \"src/vaults/BaseVaults.sol\";\n\n/// @title VaultRouter\n/// @notice This is a helper contract, designed to be the entrypoint for EOAs.\n/// It removes the need to know about all other contracts and simplifies the way to interact with the protocol.\n/// It also adds the need to fully pay for each step of the transaction execution. VaultRouter allows\n/// the caller to execute multiple function into a single transaction by taking advantage of\n/// the multicall functionality which batches message calls into a single one.\n/// @dev It is critical to ensure that at the end of any transaction, no funds remain in the\n/// VaultRouter. Any funds that do remain are at risk of being taken by other users.\ncontract VaultRouter is Auth, Multicall, Recoverable, IVaultRouter {\n using CastLib for address;\n\n /// @dev Requests for Centrifuge pool are non-fungible and all have ID = 0\n uint256 private constant REQUEST_ID = 0;\n\n IEscrow public immutable escrow;\n IGateway public immutable gateway;\n IPoolManager public immutable poolManager;\n IMessageDispatcher public immutable messageDispatcher;\n\n /// @inheritdoc IVaultRouter\n mapping(address controller => mapping(IBaseVault vault => uint256 amount)) public lockedRequests;\n\n constructor(\n address escrow_,\n IGateway gateway_,\n IPoolManager poolManager_,\n IMessageDispatcher messageDispatcher_,\n address deployer\n ) Auth(deployer) {\n escrow = IEscrow(escrow_);\n gateway = gateway_;\n poolManager = poolManager_;\n messageDispatcher = messageDispatcher_;\n }\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IMulticall\n /// @notice performs a multicall but all message sent in the process will be batched\n function multicall(bytes[] calldata data) public payable override(Multicall, IMulticall) {\n bool wasBatching = gateway.isBatching();\n if (!wasBatching) {\n gateway.startBatching();\n gateway.payTransaction{value: msg.value}(msg.sender);\n }\n\n super.multicall(data);\n\n if (!wasBatching) {\n gateway.endBatching();\n }\n }\n\n //----------------------------------------------------------------------------------------------\n // Enable interactions\n //----------------------------------------------------------------------------------------------\n\n function enable(IBaseVault vault) public payable protected {\n vault.setEndorsedOperator(msg.sender, true);\n }\n\n function disable(IBaseVault vault) external payable protected {\n vault.setEndorsedOperator(msg.sender, false);\n }\n\n //----------------------------------------------------------------------------------------------\n // Deposit\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IVaultRouter\n function requestDeposit(IAsyncVault vault, uint256 amount, address controller, address owner)\n external\n payable\n protected\n {\n require(owner == msg.sender || owner == address(this), InvalidOwner());\n\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault);\n if (owner == address(this)) {\n _approveMax(vaultDetails.asset, address(vault));\n }\n\n _pay();\n vault.requestDeposit(amount, controller, owner);\n }\n\n /// @inheritdoc IVaultRouter\n function deposit(BaseSyncDepositVault vault, uint256 assets, address receiver, address owner)\n external\n payable\n protected\n {\n require(owner == msg.sender || owner == address(this), InvalidOwner());\n require(!vault.supportsInterface(type(IERC7540Deposit).interfaceId), NonSyncDepositVault());\n\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault);\n SafeTransferLib.safeTransferFrom(vaultDetails.asset, owner, address(this), assets);\n _approveMax(vaultDetails.asset, address(vault));\n\n _pay();\n vault.deposit(assets, receiver);\n }\n\n /// @inheritdoc IVaultRouter\n function lockDepositRequest(IBaseVault vault, uint256 amount, address controller, address owner)\n public\n payable\n protected\n {\n require(owner == msg.sender || owner == address(this), InvalidOwner());\n require(vault.supportsInterface(type(IERC7540Deposit).interfaceId), NonAsyncVault());\n\n lockedRequests[controller][vault] += amount;\n\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault);\n SafeTransferLib.safeTransferFrom(vaultDetails.asset, owner, address(escrow), amount);\n\n emit LockDepositRequest(vault, controller, owner, msg.sender, amount);\n }\n\n /// @inheritdoc IVaultRouter\n function enableLockDepositRequest(IBaseVault vault, uint256 amount) external payable protected {\n enable(vault);\n\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault);\n\n uint256 assetBalance;\n assetBalance = IERC20(vaultDetails.asset).balanceOf(msg.sender);\n\n if (vaultDetails.isWrapper && assetBalance < amount) {\n wrap(vaultDetails.asset, amount, address(this), msg.sender);\n lockDepositRequest(vault, amount, msg.sender, address(this));\n } else {\n lockDepositRequest(vault, amount, msg.sender, msg.sender);\n }\n }\n\n /// @inheritdoc IVaultRouter\n function unlockDepositRequest(IBaseVault vault, address receiver) external payable protected {\n uint256 lockedRequest = lockedRequests[msg.sender][vault];\n require(lockedRequest != 0, NoLockedBalance());\n lockedRequests[msg.sender][vault] = 0;\n\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault);\n escrow.authTransferTo(vaultDetails.asset, receiver, lockedRequest);\n\n emit UnlockDepositRequest(vault, msg.sender, receiver);\n }\n\n /// @inheritdoc IVaultRouter\n function executeLockedDepositRequest(IAsyncVault vault, address controller) external payable protected {\n uint256 lockedRequest = lockedRequests[controller][vault];\n require(lockedRequest != 0, NoLockedRequest());\n lockedRequests[controller][vault] = 0;\n\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault);\n escrow.authTransferTo(vaultDetails.asset, address(this), lockedRequest);\n\n _pay();\n _approveMax(vaultDetails.asset, address(vault));\n vault.requestDeposit(lockedRequest, controller, address(this));\n emit ExecuteLockedDepositRequest(vault, controller, msg.sender);\n }\n\n /// @inheritdoc IVaultRouter\n function claimDeposit(IAsyncVault vault, address receiver, address controller) external payable protected {\n _canClaim(vault, receiver, controller);\n uint256 maxMint = vault.maxMint(controller);\n vault.mint(maxMint, receiver, controller);\n }\n\n /// @inheritdoc IVaultRouter\n function cancelDepositRequest(IAsyncVault vault) external payable protected {\n _pay();\n vault.cancelDepositRequest(REQUEST_ID, msg.sender);\n }\n\n /// @inheritdoc IVaultRouter\n function claimCancelDepositRequest(IAsyncVault vault, address receiver, address controller)\n external\n payable\n protected\n {\n _canClaim(vault, receiver, controller);\n vault.claimCancelDepositRequest(REQUEST_ID, receiver, controller);\n }\n\n //----------------------------------------------------------------------------------------------\n // Redeem\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IVaultRouter\n function requestRedeem(IAsyncVault vault, uint256 amount, address controller, address owner)\n external\n payable\n protected\n {\n require(owner == msg.sender || owner == address(this), InvalidOwner());\n _pay();\n vault.requestRedeem(amount, controller, owner);\n }\n\n /// @inheritdoc IVaultRouter\n function claimRedeem(IBaseVault vault, address receiver, address controller) external payable protected {\n _canClaim(vault, receiver, controller);\n uint256 maxWithdraw = vault.maxWithdraw(controller);\n\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault);\n if (vaultDetails.isWrapper && controller != msg.sender) {\n // Auto-unwrap if permissionlessly claiming for another controller\n vault.withdraw(maxWithdraw, address(this), controller);\n unwrap(vaultDetails.asset, maxWithdraw, receiver);\n } else {\n vault.withdraw(maxWithdraw, receiver, controller);\n }\n }\n\n /// @inheritdoc IVaultRouter\n function cancelRedeemRequest(IAsyncVault vault) external payable protected {\n _pay();\n vault.cancelRedeemRequest(REQUEST_ID, msg.sender);\n }\n\n /// @inheritdoc IVaultRouter\n function claimCancelRedeemRequest(IAsyncVault vault, address receiver, address controller)\n external\n payable\n protected\n {\n _canClaim(vault, receiver, controller);\n vault.claimCancelRedeemRequest(REQUEST_ID, receiver, controller);\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-20 permits & wrapping\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IVaultRouter\n function permit(address asset, address spender, uint256 assets, uint256 deadline, uint8 v, bytes32 r, bytes32 s)\n external\n payable\n protected\n {\n try IERC20Permit(asset).permit(msg.sender, spender, assets, deadline, v, r, s) {} catch {}\n }\n\n function wrap(address wrapper, uint256 amount, address receiver, address owner) public payable protected {\n require(owner == msg.sender || owner == address(this), InvalidOwner());\n address underlying = IERC20Wrapper(wrapper).underlying();\n\n amount = MathLib.min(amount, IERC20(underlying).balanceOf(owner));\n require(amount != 0, ZeroBalance());\n SafeTransferLib.safeTransferFrom(underlying, owner, address(this), amount);\n\n _approveMax(underlying, wrapper);\n require(IERC20Wrapper(wrapper).depositFor(receiver, amount), WrapFailed());\n }\n\n function unwrap(address wrapper, uint256 amount, address receiver) public payable protected {\n amount = MathLib.min(amount, IERC20(wrapper).balanceOf(address(this)));\n require(amount != 0, ZeroBalance());\n\n require(IERC20Wrapper(wrapper).withdrawTo(receiver, amount), UnwrapFailed());\n }\n\n //----------------------------------------------------------------------------------------------\n // View methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IVaultRouter\n function getVault(PoolId poolId, ShareClassId scId, address asset) external view returns (address) {\n return IPoolManager(poolManager).shareToken(poolId, scId).vault(asset);\n }\n\n /// @inheritdoc IVaultRouter\n function estimate(uint16 centrifugeId, bytes calldata payload) external view returns (uint256) {\n return messageDispatcher.estimate(centrifugeId, payload);\n }\n\n /// @inheritdoc IVaultRouter\n function hasPermissions(IBaseVault vault, address controller) external view returns (bool) {\n return vault.isPermissioned(controller);\n }\n\n /// @inheritdoc IVaultRouter\n function isEnabled(IBaseVault vault, address controller) public view returns (bool) {\n return vault.isOperator(controller, address(this));\n }\n\n /// @notice Gives the max approval to `to` for spending the given `asset` if not already approved.\n /// @dev Assumes that `type(uint256).max` is large enough to never have to increase the allowance again.\n function _approveMax(address asset, address spender) internal {\n if (IERC20(asset).allowance(address(this), spender) == 0) {\n SafeTransferLib.safeApprove(asset, spender, type(uint256).max);\n }\n }\n\n /// @notice Send native tokens to the gateway for transaction payment if it's not in a multicall.\n function _pay() internal {\n if (!gateway.isBatching()) {\n gateway.payTransaction{value: msg.value}(msg.sender);\n }\n }\n\n /// @notice Ensures msg.sender is either the controller, or can permissionlessly claim\n /// on behalf of the controller.\n function _canClaim(IBaseVault vault, address receiver, address controller) internal view {\n require(controller == msg.sender || (controller == receiver && isEnabled(vault, controller)), InvalidSender());\n }\n}\n" + }, + "src/vaults/factories/AsyncVaultFactory.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nimport {AsyncVault} from \"src/vaults/AsyncVault.sol\";\nimport {IVaultFactory} from \"src/vaults/interfaces/factories/IVaultFactory.sol\";\nimport {IPoolEscrowProvider} from \"src/vaults/interfaces/factories/IPoolEscrowFactory.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\nimport {IAsyncRequestManager} from \"src/vaults/interfaces/investments/IAsyncRequestManager.sol\";\nimport {IBaseVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\n\n/// @title ERC7540 Vault Factory\n/// @dev Utility for deploying new vault contracts\ncontract AsyncVaultFactory is Auth, IVaultFactory {\n address public immutable root;\n IAsyncRequestManager public immutable asyncRequestManager;\n\n constructor(address root_, IAsyncRequestManager asyncRequestManager_, address deployer) Auth(deployer) {\n root = root_;\n asyncRequestManager = asyncRequestManager_;\n }\n\n /// @inheritdoc IVaultFactory\n function newVault(\n PoolId poolId,\n ShareClassId scId,\n address asset,\n uint256 tokenId,\n IShareToken token,\n address[] calldata wards_\n ) public auth returns (IBaseVault) {\n require(tokenId == 0, UnsupportedTokenId());\n AsyncVault vault = new AsyncVault(poolId, scId, asset, token, root, asyncRequestManager);\n\n vault.rely(root);\n vault.rely(address(asyncRequestManager));\n uint256 wardsCount = wards_.length;\n for (uint256 i; i < wardsCount; i++) {\n vault.rely(wards_[i]);\n }\n\n vault.deny(address(this));\n return vault;\n }\n}\n" + }, + "src/vaults/factories/PoolEscrowFactory.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\n\nimport {IPoolEscrowProvider, IPoolEscrowFactory} from \"src/vaults/interfaces/factories/IPoolEscrowFactory.sol\";\nimport {IPoolEscrow} from \"src/vaults/interfaces/IEscrow.sol\";\nimport {PoolEscrow} from \"src/vaults/Escrow.sol\";\n\ncontract PoolEscrowFactory is Auth, IPoolEscrowFactory {\n address public immutable root;\n\n address public gateway;\n address public poolManager;\n address public balanceSheet;\n address public asyncRequestManager;\n\n constructor(address root_, address deployer) Auth(deployer) {\n root = root_;\n }\n\n /// @inheritdoc IPoolEscrowFactory\n function file(bytes32 what, address data) external auth {\n if (what == \"poolManager\") poolManager = data;\n else if (what == \"gateway\") gateway = data;\n else if (what == \"balanceSheet\") balanceSheet = data;\n else if (what == \"asyncRequestManager\") asyncRequestManager = data;\n else revert FileUnrecognizedParam();\n emit File(what, data);\n }\n\n /// @inheritdoc IPoolEscrowFactory\n function newEscrow(PoolId poolId) public auth returns (IPoolEscrow) {\n PoolEscrow escrow_ = new PoolEscrow{salt: bytes32(uint256(poolId.raw()))}(poolId, address(this));\n\n escrow_.rely(root);\n escrow_.rely(gateway);\n escrow_.rely(poolManager);\n escrow_.rely(balanceSheet);\n escrow_.rely(asyncRequestManager);\n\n escrow_.deny(address(this));\n\n emit DeployPoolEscrow(poolId, address(escrow_));\n return IPoolEscrow(escrow_);\n }\n\n /// @inheritdoc IPoolEscrowProvider\n function escrow(PoolId poolId) external view returns (IPoolEscrow) {\n bytes32 salt = bytes32(uint256(poolId.raw()));\n bytes32 hash = keccak256(\n abi.encodePacked(\n bytes1(0xff),\n address(this),\n salt,\n keccak256(abi.encodePacked(type(PoolEscrow).creationCode, abi.encode(poolId, address(this))))\n )\n );\n\n return IPoolEscrow(address(uint160(uint256(hash))));\n }\n}\n" + }, + "src/vaults/factories/SyncDepositVaultFactory.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nimport {SyncDepositVault} from \"src/vaults/SyncDepositVault.sol\";\nimport {IVaultFactory} from \"src/vaults/interfaces/factories/IVaultFactory.sol\";\nimport {IAsyncRedeemManager} from \"src/vaults/interfaces/investments/IAsyncRedeemManager.sol\";\nimport {ISyncDepositManager} from \"src/vaults/interfaces/investments/ISyncDepositManager.sol\";\nimport {IPoolEscrowProvider} from \"src/vaults/interfaces/factories/IPoolEscrowFactory.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\nimport {IBaseVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\n\n/// @title Sync Vault Factory\n/// @dev Utility for deploying new vault contracts\ncontract SyncDepositVaultFactory is Auth, IVaultFactory {\n address public immutable root;\n ISyncDepositManager public immutable syncDepositManager;\n IAsyncRedeemManager public immutable asyncRedeemManager;\n\n constructor(\n address root_,\n ISyncDepositManager syncDepositManager_,\n IAsyncRedeemManager asyncRedeemManager_,\n address deployer\n ) Auth(deployer) {\n root = root_;\n syncDepositManager = syncDepositManager_;\n asyncRedeemManager = asyncRedeemManager_;\n }\n\n /// @inheritdoc IVaultFactory\n function newVault(\n PoolId poolId,\n ShareClassId scId,\n address asset,\n uint256 tokenId,\n IShareToken token,\n address[] calldata wards_\n ) public auth returns (IBaseVault) {\n require(tokenId == 0, UnsupportedTokenId());\n SyncDepositVault vault =\n new SyncDepositVault(poolId, scId, asset, token, root, syncDepositManager, asyncRedeemManager);\n\n vault.rely(root);\n vault.rely(address(syncDepositManager));\n vault.rely(address(asyncRedeemManager));\n\n uint256 wardsCount = wards_.length;\n for (uint256 i; i < wardsCount; i++) {\n vault.rely(wards_[i]);\n }\n\n vault.deny(address(this));\n return vault;\n }\n}\n" + }, + "src/vaults/factories/TokenFactory.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\n\nimport {ShareToken} from \"src/vaults/token/ShareToken.sol\";\nimport {ITokenFactory} from \"src/vaults/interfaces/factories/ITokenFactory.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\n\n/// @title Share Token Factory\n/// @dev Utility for deploying new share class token contracts\n/// Ensures the addresses are deployed at a deterministic address\n/// based on the pool id and share class id.\ncontract TokenFactory is Auth, ITokenFactory {\n address public immutable root;\n\n constructor(address _root, address deployer) Auth(deployer) {\n root = _root;\n }\n\n /// @inheritdoc ITokenFactory\n function newToken(\n string memory name,\n string memory symbol,\n uint8 decimals,\n bytes32 salt,\n address[] calldata tokenWards\n ) public auth returns (IShareToken) {\n ShareToken token = new ShareToken{salt: salt}(decimals);\n\n token.file(\"name\", name);\n token.file(\"symbol\", symbol);\n\n token.rely(root);\n uint256 wardsCount = tokenWards.length;\n for (uint256 i; i < wardsCount; i++) {\n token.rely(tokenWards[i]);\n }\n token.deny(address(this));\n\n return token;\n }\n\n /// @inheritdoc ITokenFactory\n function getAddress(uint8 decimals, bytes32 salt) external view returns (address) {\n bytes32 hash = keccak256(\n abi.encodePacked(\n bytes1(0xff),\n address(this),\n salt,\n keccak256(abi.encodePacked(type(ShareToken).creationCode, abi.encode(decimals)))\n )\n );\n\n return address(uint160(uint256(hash)));\n }\n}\n" + }, + "src/vaults/interfaces/IBalanceSheet.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {D18, d18} from \"src/misc/types/D18.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\n\nstruct QueueAmount {\n // Issuances of shares / deposits of assets\n uint128 increase;\n // Revocations of shares / withdraws of assets\n uint128 decrease;\n}\n\ninterface IBalanceSheet {\n // --- Events ---\n event File(bytes32 indexed what, address data);\n event UpdateManager(PoolId indexed poolId, address who, bool canManage);\n event Withdraw(\n PoolId indexed poolId,\n ShareClassId indexed scId,\n address asset,\n uint256 tokenId,\n address receiver,\n uint128 amount,\n D18 pricePoolPerAsset\n );\n event Deposit(\n PoolId indexed poolId,\n ShareClassId indexed scId,\n address asset,\n uint256 tokenId,\n address provider,\n uint128 amount,\n D18 pricePoolPerAsset\n );\n event Issue(PoolId indexed poolId, ShareClassId indexed scId, address to, D18 pricePoolPerShare, uint128 shares);\n event Revoke(PoolId indexed poolId, ShareClassId indexed scId, address from, D18 pricePoolPerShare, uint128 shares);\n\n // --- Errors ---\n error FileUnrecognizedParam();\n error CannotTransferFromEndorsedContract();\n\n /// @notice Overloaded increase with asset transfer\n function deposit(PoolId poolId, ShareClassId scId, address asset, uint256 tokenId, address provider, uint128 amount)\n external;\n\n function noteDeposit(\n PoolId poolId,\n ShareClassId scId,\n address asset,\n uint256 tokenId,\n address provider,\n uint128 amount\n ) external;\n\n function withdraw(\n PoolId poolId,\n ShareClassId scId,\n address asset,\n uint256 tokenId,\n address receiver,\n uint128 amount\n ) external;\n\n function issue(PoolId poolId, ShareClassId scId, address to, uint128 shares) external;\n\n function revoke(PoolId poolId, ShareClassId scId, address from, uint128 shares) external;\n\n function noteRevoke(PoolId poolId, ShareClassId scId, address from, uint128 shares) external;\n\n function transferSharesFrom(PoolId poolId, ShareClassId scId, address from, address to, uint256 amount) external;\n\n function overridePricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId, D18 value) external;\n\n function overridePricePoolPerShare(PoolId poolId, ShareClassId scId, D18 value) external;\n}\n" + }, + "src/vaults/interfaces/IBaseVaults.sol": { + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.5.0;\n\nenum VaultKind {\n /// @dev Refers to AsyncVault\n Async,\n /// @dev not yet supported\n Sync,\n /// @dev Refers to SyncDepositVault\n SyncDepositAsyncRedeem\n}\n\nimport {IERC7575, IERC165} from \"src/misc/interfaces/IERC7575.sol\";\nimport {\n IERC7540Operator,\n IERC7714,\n IERC7741,\n IERC7540Redeem,\n IERC7887Redeem,\n IERC7887Deposit,\n IERC7540Deposit\n} from \"src/misc/interfaces/IERC7540.sol\";\nimport {IRecoverable} from \"src/misc/interfaces/IRecoverable.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nimport {IBaseRequestManager} from \"src/vaults/interfaces/investments/IBaseRequestManager.sol\";\nimport {IAsyncRedeemManager} from \"src/vaults/interfaces/investments/IAsyncRedeemManager.sol\";\n\n/// @notice Interface for the all vault contracts\n/// @dev Must be implemented by all vaults\ninterface IBaseVault is IERC7540Operator, IERC7741, IERC7714, IERC7575, IRecoverable {\n error FileUnrecognizedParam();\n error NotEndorsed();\n error CannotSetSelfAsOperator();\n error ExpiredAuthorization();\n error AlreadyUsedAuthorization();\n error InvalidAuthorization();\n error InvalidController();\n error InsufficientBalance();\n error RequestRedeemFailed();\n error TransferFromFailed();\n\n event File(bytes32 indexed what, address data);\n\n /// @notice Identifier of the Centrifuge pool\n function poolId() external view returns (PoolId);\n\n /// @notice Identifier of the share class of the Centrifuge pool\n function scId() external view returns (ShareClassId);\n\n /// @notice Set msg.sender as operator of owner, to `approved` status\n /// @dev MUST be called by endorsed sender\n function setEndorsedOperator(address owner, bool approved) external;\n\n /// @notice Returns the base investment manager contract handling the vault.\n /// @dev This naming MUST NOT change due to requirements of legacy vaults (v2)\n /// @return IBaseRequestManager The address of the manager contract that is between vault and gateway\n function manager() external view returns (IBaseRequestManager);\n\n /// @notice Checks whether the vault is partially (a)synchronous.\n ///\n /// @return vaultKind_ The kind of the vault\n function vaultKind() external view returns (VaultKind vaultKind_);\n}\n\n/**\n * @title IAsyncRedeemVault\n * @dev This is the specific set of interfaces used by the Centrifuge implementation of ERC7540,\n * as a fully asynchronous Vault, with cancellation support, and authorize operator signature support.\n */\ninterface IAsyncRedeemVault is IERC7540Redeem, IERC7887Redeem, IBaseVault {\n event RedeemClaimable(address indexed controller, uint256 indexed requestId, uint256 assets, uint256 shares);\n event CancelRedeemClaimable(address indexed controller, uint256 indexed requestId, uint256 shares);\n\n /// @notice Callback when a redeem Request is triggered externally;\n function onRedeemRequest(address controller, address owner, uint256 shares) external;\n\n /// @notice Callback when a redeem Request becomes claimable\n function onRedeemClaimable(address owner, uint256 assets, uint256 shares) external;\n\n /// @notice Callback when a claim redeem Request becomes claimable\n function onCancelRedeemClaimable(address owner, uint256 shares) external;\n\n /// @notice Retrieve the asynchronous redeem manager\n function asyncRedeemManager() external view returns (IAsyncRedeemManager);\n}\n\ninterface IAsyncVault is IERC7540Deposit, IERC7887Deposit, IAsyncRedeemVault {\n event DepositClaimable(address indexed controller, uint256 indexed requestId, uint256 assets, uint256 shares);\n event CancelDepositClaimable(address indexed controller, uint256 indexed requestId, uint256 assets);\n\n error InvalidOwner();\n error RequestDepositFailed();\n\n /// @notice Callback when a deposit Request becomes claimable\n function onDepositClaimable(address owner, uint256 assets, uint256 shares) external;\n\n /// @notice Callback when a claim deposit Request becomes claimable\n function onCancelDepositClaimable(address owner, uint256 assets) external;\n}\n" + }, + "src/vaults/interfaces/IEscrow.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IRecoverable} from \"src/misc/Recoverable.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\n/// @title Escrow for holding assets\ninterface IEscrow {\n // --- Events ---\n /// @notice Emitted when an authTransferTo is made\n /// @dev Needed as allowances increase attack surface\n event AuthTransferTo(address indexed asset, uint256 indexed tokenId, address reciver, uint256 value);\n\n /// @notice Emitted when the escrow has insufficient balance for an action - virtual or actual balance\n error InsufficientBalance(address asset, uint256 tokenId, uint256 value, uint256 balance);\n\n /// @notice\n function authTransferTo(address asset, uint256 tokenId, address receiver, uint256 value) external;\n\n /// @notice\n function authTransferTo(address asset, address receiver, uint256 value) external;\n}\n\nstruct Holding {\n uint128 total;\n uint128 reserved;\n}\n\n/// @title PerPoolEscrow separating funds by pool and share class\ninterface IPoolEscrow is IEscrow, IRecoverable {\n // --- Events ---\n /// @notice Emitted when a deposit is made\n /// @param asset The address of the deposited asset\n /// @param tokenId The id of the asset - 0 for ERC20\n /// @param poolId The id of the pool\n /// @param scId The id of the share class\n /// @param value The amount deposited\n event Deposit(\n address indexed asset, uint256 indexed tokenId, PoolId indexed poolId, ShareClassId scId, uint128 value\n );\n\n /// @notice Emitted when an amount is reserved\n /// @param asset The address of the reserved asset\n /// @param tokenId The id of the asset - 0 for ERC20\n /// @param poolId The id of the pool\n /// @param scId The id of the share class\n /// @param value The delta amount reserved\n /// @param value The new absolute amount reserved\n event IncreaseReserve(\n address indexed asset,\n uint256 indexed tokenId,\n PoolId indexed poolId,\n ShareClassId scId,\n uint256 delta,\n uint128 value\n );\n\n /// @notice Emitted when an amount is unreserved\n /// @param asset The address of the reserved asset\n /// @param tokenId The id of the asset - 0 for ERC20\n /// @param poolId The id of the pool\n /// @param scId The id of the share class\n /// @param value The delta amount unreserved\n /// @param value The new absolute amount reserved\n event DecreaseReserve(\n address indexed asset,\n uint256 indexed tokenId,\n PoolId indexed poolId,\n ShareClassId scId,\n uint256 delta,\n uint128 value\n );\n\n /// @notice Emitted when a withdraw is made\n /// @param asset The address of the withdrawn asset\n /// @param tokenId The id of the asset - 0 for ERC20\n /// @param poolId The id of the pool\n /// @param scId The id of the share class\n /// @param value The amount withdrawn\n event Withdraw(\n address indexed asset, uint256 indexed tokenId, PoolId indexed poolId, ShareClassId scId, uint128 value\n );\n\n // --- Errors ---\n /// @notice Dispatched when the balance of the escrow did not increase sufficiently\n error InsufficientDeposit();\n\n /// @notice Dispatched when the outstanding reserved amount is insufficient for the decrease\n error InsufficientReservedAmount();\n\n // --- Functions ---\n /// @notice Deposits `value` of `asset` in underlying `poolId` and given `scId`\n ///\n /// @dev NOTE: Must ensure balance sufficiency, i.e. that the depositing amount does not exceed the balance of\n /// escrow\n ///\n /// @param scId The id of the share class\n /// @param asset The address of the asset to be deposited\n /// @param tokenId The id of the asset - 0 for ERC20\n /// @param value The amount to deposit\n function deposit(ShareClassId scId, address asset, uint256 tokenId, uint128 value) external;\n\n /// @notice Withdraws `value` of `asset` in underlying `poolId` and given `scId`\n /// @dev MUST ensure that reserved amounts are not withdrawn\n /// @param scId The id of the share class\n /// @param asset The address of the asset to be withdrawn\n /// @param tokenId The id of the asset - 0 for ERC20\n /// @param value The amount to withdraw\n function withdraw(ShareClassId scId, address asset, uint256 tokenId, uint128 value) external;\n\n /// @notice Increases the reserved amount of `value` for `asset` in underlying `poolId` and given `scId`\n /// @dev MUST prevent the reserved amount from being withdrawn\n /// @param scId The id of the share class\n /// @param asset The address of the asset to be reserved\n /// @param tokenId The id of the asset - 0 for ERC20\n /// @param value The amount to reserve\n function reserveIncrease(ShareClassId scId, address asset, uint256 tokenId, uint128 value) external;\n\n /// @notice Decreases the reserved amount of `value` for `asset` in underlying `poolId` and given `scId`\n /// @dev MUST fail if `value` is greater than the current reserved amount\n /// @param scId The id of the share class\n /// @param asset The address of the asset to be reserved\n /// @param tokenId The id of the asset - 0 for ERC20\n /// @param value The amount to decrease\n function reserveDecrease(ShareClassId scId, address asset, uint256 tokenId, uint128 value) external;\n\n /// @notice Provides the available balance of `asset` in underlying `poolId` and given `scId`\n /// @dev MUST return the balance minus the reserved amount\n /// @param scId The id of the share class\n /// @param asset The address of the asset to be checked\n /// @param tokenId The id of the asset - 0 for ERC20\n /// @return The available balance\n function availableBalanceOf(ShareClassId scId, address asset, uint256 tokenId) external view returns (uint128);\n}\n" + }, + "src/vaults/interfaces/IPoolManager.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {D18, d18} from \"src/misc/types/D18.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\n\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\nimport {IVaultFactory} from \"src/vaults/interfaces/factories/IVaultFactory.sol\";\nimport {IBaseVault, VaultKind} from \"src/vaults/interfaces/IBaseVaults.sol\";\n\n/// @dev Centrifuge pools\nstruct Pool {\n uint256 createdAt;\n mapping(ShareClassId scId => ShareClassDetails) shareClasses;\n}\n\n/// @dev Each Centrifuge pool is associated to 1 or more shar classes\nstruct ShareClassDetails {\n IShareToken shareToken;\n /// @dev Each share class has an individual price per share class unit in pool denomination (POOL_UNIT/SHARE_UNIT)\n Price pricePoolPerShare;\n /// @dev Each share class can have multiple vaults deployed,\n /// multiple vaults can be linked to the same asset.\n /// A vault in this storage DOES NOT mean the vault can be used\n mapping(address asset => mapping(uint256 tokenId => IBaseVault[])) vaults;\n /// @dev For each share class, we store the price per pool unit in asset denomination (POOL_UNIT/ASSET_UNIT)\n mapping(address asset => mapping(uint256 tokenId => Price)) pricePoolPerAsset;\n}\n\n/// @dev Price struct that contains a price, the timestamp at which it was computed and the max age of the price.\nstruct Price {\n uint128 price;\n uint64 computedAt;\n uint64 maxAge;\n}\n\n/// @dev Checks if a price is valid. Returns false if price is 0 or computedAt is 0. Otherwise checks for block\n/// timestamp <= computedAt + maxAge\nfunction isValid(Price memory price) view returns (bool) {\n if (price.computedAt != 0 && price.price != 0) {\n return block.timestamp <= price.validUntil();\n } else {\n return false;\n }\n}\n\n/// @dev Computes the timestamp until the price is valid. Saturates at uint64.MAX.\nfunction validUntil(Price memory price) pure returns (uint64) {\n unchecked {\n uint64 validUntil_ = price.computedAt + price.maxAge;\n if (validUntil_ < price.computedAt) {\n return type(uint64).max;\n }\n return validUntil_;\n }\n}\n\n/// @dev Retrieves the price as an D18 from the struct\nfunction asPrice(Price memory price) pure returns (D18) {\n return d18(price.price);\n}\n\nusing {isValid, asPrice, validUntil} for Price global;\n\nstruct VaultDetails {\n /// @dev AssetId of the asset\n AssetId assetId;\n /// @dev Address of the asset\n address asset;\n /// @dev TokenId of the asset - zero if asset is ERC20, non-zero if asset is ERC6909\n uint256 tokenId;\n /// @dev Whether this wrapper conforms to the IERC20Wrapper interface\n bool isWrapper;\n /// @dev Whether the vault is linked to a share class atm\n bool isLinked;\n}\n\nstruct AssetIdKey {\n /// @dev The address of the asset\n address asset;\n /// @dev The ERC6909 token id or 0, if the underlying asset is an ERC20\n uint256 tokenId;\n}\n\ninterface IPoolManager {\n event File(bytes32 indexed what, address data);\n event RegisterAsset(\n AssetId indexed assetId,\n address indexed asset,\n uint256 indexed tokenId,\n string name,\n string symbol,\n uint8 decimals\n );\n event File(bytes32 indexed what, address factory, bool status);\n event AddPool(PoolId indexed poolId);\n event AddShareClass(PoolId indexed poolId, ShareClassId indexed scId, IShareToken token);\n event DeployVault(\n PoolId indexed poolId,\n ShareClassId indexed scId,\n address indexed asset,\n uint256 tokenId,\n IVaultFactory factory,\n IBaseVault vault,\n VaultKind kind\n );\n event PriceUpdate(\n PoolId indexed poolId,\n ShareClassId indexed scId,\n address indexed asset,\n uint256 tokenId,\n uint256 price,\n uint64 computedAt\n );\n event PriceUpdate(PoolId indexed poolId, ShareClassId indexed scId, uint256 price, uint64 computedAt);\n event TransferShares(\n uint16 centrifugeId,\n PoolId indexed poolId,\n ShareClassId indexed scId,\n address indexed sender,\n bytes32 destinationAddress,\n uint128 amount\n );\n event UpdateContract(PoolId indexed poolId, ShareClassId indexed scId, address target, bytes payload);\n event LinkVault(\n PoolId indexed poolId, ShareClassId indexed scId, address indexed asset, uint256 tokenId, IBaseVault vault\n );\n event UnlinkVault(\n PoolId indexed poolId, ShareClassId indexed scId, address indexed asset, uint256 tokenId, IBaseVault vault\n );\n event UpdateMaxSharePriceAge(PoolId indexed poolId, ShareClassId indexed scId, uint64 maxPriceAge);\n event UpdateMaxAssetPriceAge(\n PoolId indexed poolId, ShareClassId indexed scId, address indexed asset, uint256 tokenId, uint64 maxPriceAge\n );\n\n error FileUnrecognizedParam();\n error TooFewDecimals();\n error TooManyDecimals();\n error PoolAlreadyAdded();\n error InvalidPool();\n error ShareClassAlreadyRegistered();\n error InvalidHook();\n error OldMetadata();\n error CannotSetOlderPrice();\n error OldHook();\n error UnknownVault();\n error UnknownAsset();\n error MalformedVaultUpdateMessage();\n error UnknownToken();\n error InvalidFactory();\n error InvalidPrice();\n error AssetMissingDecimals();\n error ShareTokenDoesNotExist();\n error LocalTransferNotAllowed();\n error CrossChainTransferNotAllowed();\n error ShareTokenTransferFailed();\n error TransferFromFailed();\n\n /// @notice Returns the asset address and tokenId associated with a given asset id.\n /// @dev Reverts if asset id does not exist\n ///\n /// @param assetId The underlying internal uint128 assetId.\n /// @return asset The address of the asset linked to the given asset id.\n /// @return tokenId The token id corresponding to the asset, i.e. zero if ERC20 or non-zero if ERC6909.\n function idToAsset(AssetId assetId) external view returns (address asset, uint256 tokenId);\n\n /// @notice Returns assetId given the asset address and tokenId.\n /// @dev Reverts if asset id does not exist\n ///\n /// @param asset The address of the asset linked to the given asset id.\n /// @param tokenId The token id corresponding to the asset, i.e. zero if ERC20 or non-zero if ERC6909.\n /// @return assetId The underlying internal uint128 assetId.\n function assetToId(address asset, uint256 tokenId) external view returns (AssetId assetId);\n\n /// @notice Updates a contract parameter\n /// @param what Accepts a bytes32 representation of 'gateway', 'investmentManager', 'tokenFactory',\n /// 'vaultFactory', or 'gasService'\n function file(bytes32 what, address data) external;\n\n /// @notice Updates a contract parameter\n /// @param what Accepts a bytes32 representation of 'vaultFactory'\n function file(bytes32 what, address factory, bool status) external;\n\n /// @notice transfers share class tokens to a cross-chain recipient address\n /// @dev To transfer to evm chains, pad a 20 byte evm address with 12 bytes of 0\n /// @param centrifugeId The destination chain id\n /// @param poolId The centrifuge pool id\n /// @param scId The share class id\n /// @param receiver A bytes32 representation of the receiver address\n /// @param amount The amount of tokens to transfer\n function transferShares(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bytes32 receiver, uint128 amount)\n external\n payable;\n\n /// @notice Registers an ERC-20 or ERC-6909 asset in another chain.\n /// @dev `decimals()` MUST return a `uint8` value between 2 and 18.\n /// @dev `name()` and `symbol()` MAY return no values.\n ///\n /// @param centrifugeId The centrifuge id of chain to where the shares are transferred\n /// @param asset The address of the asset to be registered\n /// @param tokenId The token id corresponding to the asset, i.e. zero if ERC20 or non-zero if ERC6909.\n /// @return assetId The underlying internal uint128 assetId.\n function registerAsset(uint16 centrifugeId, address asset, uint256 tokenId)\n external\n payable\n returns (AssetId assetId);\n\n /// @notice Deploys a new vault\n ///\n /// @param poolId The pool id\n /// @param scId The share class id\n /// @param assetId The asset id for which we want to deploy a vault\n /// @param factory The address of the corresponding vault factory\n /// @return address The address of the deployed vault\n function deployVault(PoolId poolId, ShareClassId scId, AssetId assetId, IVaultFactory factory)\n external\n returns (IBaseVault);\n\n /// @notice Links a deployed vault to the given pool, share class and asset.\n ///\n /// @param poolId The pool id\n /// @param scId The share class id\n /// @param assetId The asset id for which we want to deploy a vault\n /// @param vault The address of the deployed vault\n function linkVault(PoolId poolId, ShareClassId scId, AssetId assetId, IBaseVault vault) external;\n\n /// @notice Removes the link between a vault and the given pool, share class and asset.\n ///\n /// @param poolId The pool id\n /// @param scId The share class id\n /// @param assetId The asset id for which we want to deploy a vault\n /// @param vault The address of the deployed vault\n function unlinkVault(PoolId poolId, ShareClassId scId, AssetId assetId, IBaseVault vault) external;\n\n /// @notice Returns whether the given pool id is active\n function isPoolActive(PoolId poolId) external view returns (bool);\n\n /// @notice Returns the share class token for a given pool and share class id.\n /// @dev Reverts if share class does not exists\n ///\n /// @param poolId The pool id\n /// @param scId The share class id\n /// @return address The address of the share token\n function shareToken(PoolId poolId, ShareClassId scId) external view returns (IShareToken);\n\n /// @notice Function to get the details of a vault\n /// @dev Reverts if vault does not exist\n ///\n /// @param vault The address of the vault to be checked for\n /// @return details The details of the vault including the underlying asset address, token id, asset id\n function vaultDetails(IBaseVault vault) external view returns (VaultDetails memory details);\n\n /// @notice Checks whether a given asset-vault pair is eligible for investing into a share class of a pool\n ///\n /// @param poolId The pool id\n /// @param scId The share class id\n /// @param asset The address of the asset\n /// @param vault The address of the vault\n /// @return bool Whether vault is to a share class\n function isLinked(PoolId poolId, ShareClassId scId, address asset, IBaseVault vault) external view returns (bool);\n\n /// @notice Returns the price per share for a given pool, share class, asset, and asset id. The provided price is\n /// defined as ASSET_UNIT/SHARE_UNIT.\n /// @dev Conditionally checks if price is valid.\n ///\n /// @dev NOTE: Should never be used for calculating amounts due to precision loss. Instead, please refer to\n /// conversion relying on pricePoolPerShare and pricePoolPerAsset. See PricingLib for more information.\n ///\n /// @param poolId The pool id\n /// @param scId The share class id\n /// @param assetId The asset id for which we want to know the ASSET_UNIT/SHARE_UNIT price\n /// @param checkValidity Whether to check if the price is valid\n /// @return price The asset price per share\n function priceAssetPerShare(PoolId poolId, ShareClassId scId, AssetId assetId, bool checkValidity)\n external\n view\n returns (D18 price);\n\n /// @notice Returns the price per share for a given pool and share class. The Provided price is defined as\n /// POOL_UNIT/SHARE_UNIT.\n /// @dev Conditionally checks if price is valid.\n ///\n /// @param poolId The pool id\n /// @param scId The share class id\n /// @param checkValidity Whether to check if the price is valid\n /// @return price The pool price per share\n function pricePoolPerShare(PoolId poolId, ShareClassId scId, bool checkValidity)\n external\n view\n returns (D18 price);\n\n /// @notice Returns the price per asset for a given pool, share class and the underlying asset id. The Provided\n /// price is defined as POOL_UNIT/ASSET_UNIT.\n /// @dev Conditionally checks if price is valid.\n ///\n /// @param poolId The pool id\n /// @param scId The share class id\n /// @param assetId The asset id for which we want to know the POOL_UNIT/ASSET_UNIT.\n /// @param checkValidity Whether to check if the price is valid\n /// @return price The pool price per asset unit\n function pricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId, bool checkValidity)\n external\n view\n returns (D18 price);\n\n /// @notice Returns the both prices per pool for a given pool, share class and the underlying asset id. The Provided\n /// prices is defined as POOL_UNIT/ASSET_UNIT and POOL_UNIT/SHARE_UNIT.\n /// @dev Conditionally checks if prices are valid.\n ///\n /// @param poolId The pool id\n /// @param scId The share class id\n /// @param assetId The asset id for which we want to know pool price per asset\n /// @param checkValidity Whether to check if the prices are valid\n /// @return pricePoolPerAsset The pool price per asset unit, i.e. POOL_UNIT/ASSET_UNIT\n /// @return pricePoolPerShare The pool price per share unit, i.e. POOL_UNIT/SHARE_UNIT\n function pricesPoolPer(PoolId poolId, ShareClassId scId, AssetId assetId, bool checkValidity)\n external\n view\n returns (D18 pricePoolPerAsset, D18 pricePoolPerShare);\n\n /// @notice Returns the age related markers for a share class price\n ///\n /// @param poolId The pool id\n /// @param scId The share class id\n /// @return computedAt The timestamp when this price was computed\n /// @return maxAge The maximum age this price is allowed to have\n /// @return validUntil The timestamp until this price is valid\n function markersPricePoolPerShare(PoolId poolId, ShareClassId scId)\n external\n view\n returns (uint64 computedAt, uint64 maxAge, uint64 validUntil);\n\n /// @notice Returns the age related markers for an asset price\n ///\n /// @param poolId The pool id\n /// @param scId The share class id\n /// @param assetId The asset id for which we want to know pool price per asset\n /// @return computedAt The timestamp when this price was computed\n /// @return maxAge The maximum age this price is allowed to have\n /// @return validUntil The timestamp until this price is valid\n function markersPricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId)\n external\n view\n returns (uint64 computedAt, uint64 maxAge, uint64 validUntil);\n}\n" + }, + "src/vaults/interfaces/IUpdateContract.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\n\ninterface IUpdateContract {\n error UnknownUpdateContractType();\n\n /// @notice Triggers an update on the target contract.\n /// @param poolId The centrifuge pool id\n /// @param scId The share class id\n /// @param payload The payload to be processed by the target address\n function update(PoolId poolId, ShareClassId scId, bytes calldata payload) external;\n}\n" + }, + "src/vaults/interfaces/IVaultRouter.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IMulticall} from \"src/misc/interfaces/IMulticall.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {IBaseVault, IAsyncVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\nimport {BaseSyncDepositVault} from \"src/vaults/BaseVaults.sol\";\n\ninterface IVaultRouter is IMulticall {\n // --- Events ---\n event LockDepositRequest(\n IBaseVault indexed vault, address indexed controller, address indexed owner, address sender, uint256 amount\n );\n event UnlockDepositRequest(IBaseVault indexed vault, address indexed controller, address indexed receiver);\n event ExecuteLockedDepositRequest(IBaseVault indexed vault, address indexed controller, address sender);\n\n error InvalidOwner();\n error NoLockedBalance();\n error NoLockedRequest();\n error ZeroBalance();\n error WrapFailed();\n error UnwrapFailed();\n error InvalidSender();\n error NonSyncDepositVault();\n error NonAsyncVault();\n\n /// @notice Check how much of the `vault`'s asset is locked for the current `controller`.\n /// @dev This is a getter method\n function lockedRequests(address controller, IBaseVault vault) external view returns (uint256 amount);\n\n // --- Manage permissionless claiming ---\n /// @notice Enable permissionless claiming\n /// @dev After this is called, anyone can claim tokens to msg.sender.\n /// Even any requests submitted directly to the vault (not through the VaultRouter) will be\n /// permissionlessly claimable through the VaultRouter, until `disable()` is called.\n function enable(IBaseVault vault) external payable;\n\n /// @notice Disable permissionless claiming\n function disable(IBaseVault vault) external payable;\n\n // --- Deposit ---\n /// @notice Check `IERC7540Deposit.requestDeposit`.\n /// @dev This adds a mandatory prepayment for all the costs that will incur during the transaction.\n /// The caller must call `VaultRouter.estimate` to get estimates how much the deposit will cost.\n ///\n /// @param vault The vault to deposit into\n /// @param amount Check @param IERC7540Deposit.requestDeposit.assets\n /// @param controller Check @param IERC7540Deposit.requestDeposit.controller\n /// @param owner Check @param IERC7540Deposit.requestDeposit.owner\n function requestDeposit(IAsyncVault vault, uint256 amount, address controller, address owner) external payable;\n\n /// @notice Check `IERC4626.deposit`.\n /// @dev This adds a mandatory prepayment for all the costs that will incur during the transaction.\n /// The caller must call `VaultRouter.estimate` to get estimates how much the deposit will cost.\n ///\n /// @param vault The vault to deposit into\n /// @param assets Check @param IERC4626.deposit.assets\n /// @param receiver Check @param IERC4626.deposit.receiver\n /// @param owner User from which to transfer the assets, either msg.sender or the VaultRouter\n function deposit(BaseSyncDepositVault vault, uint256 assets, address receiver, address owner) external payable;\n\n /// @notice Locks `amount` of `vault`'s asset in an escrow before actually sending a deposit LockDepositRequest\n /// There are users that would like to interact with the protocol but don't have permissions yet. They can\n /// lock the funds they would like to deposit beforehand.\n /// Once permissions are granted, anyone can deposit on\n /// their behalf by calling `executeLockedDepositRequest`.\n ///\n /// Example: DAO with onchain governance, that wants to invest their treasury\n /// The process that doesn't include calling this method is as follows:\n ///\n /// 1. The DAO signs the legal agreements for the pool => no onchain action,\n /// but only after this the issuer can call update_member to add them as a whitelisted investor\n /// 2. Call `requestDeposit` to lock funds\n /// 3. After the pool has fulfilled their request, call `deposit` to claim their share class tokens\n ///\n ///\n /// With the new router function the steps are as follows:\n ///\n /// 1. DAO signs the legal agreement + calls `openLockDepositRequest` in 1 governance proposal\n ///\n /// 2. Issuer then gives them permissions, then calls `executeLockDepositFunds` for them,\n /// then fulfills the request, then calls `claimDeposit` for them\n ///\n /// @dev For initial interaction better use `openLockDepositRequest` which includes some of the message calls\n /// that the caller must do execute before calling `lockDepositRequest`\n ///\n /// @param vault The address of the vault to invest in\n /// @param amount Amount to invest\n /// @param controller Address of the owner of the position\n /// @param owner Where the funds to be deposited will be take from\n function lockDepositRequest(IBaseVault vault, uint256 amount, address controller, address owner) external payable;\n\n /// @notice Helper method to lock a deposit request, and enable permissionless claiming of that vault in 1 call.\n /// @dev It starts interaction with the vault by calling `open`.\n /// Vaults support assets that are wrapped one. When user calls this method\n /// and the vault's asset is a wrapped one, first the balance of the wrapped asset is checked.\n /// If balance >= `amount`, then this asset is used\n /// else amount is treat as an underlying asset one and it is wrapped.\n /// @param vault Address of the vault\n /// @param amount Amount to be deposited\n function enableLockDepositRequest(IBaseVault vault, uint256 amount) external payable;\n\n /// @notice Unlocks all deposited assets of the current caller for a given vault\n ///\n /// @param vault Address of the vault for which funds were locked\n /// @param receiver Address of the received of the unlocked funds\n function unlockDepositRequest(IBaseVault vault, address receiver) external payable;\n\n /// @notice After the controller is given permissions, anyone can call this method and\n /// actually request a deposit with the locked funds on the behalf of the `controller`\n /// @param vault The vault for which funds are locked\n /// @param controller Owner of the deposit position\n function executeLockedDepositRequest(IAsyncVault vault, address controller) external payable;\n\n /// @notice Check IERC7540Deposit.mint\n /// @param vault Address of the vault\n /// @param receiver Check IERC7540Deposit.mint.receiver\n /// @param controller Check IERC7540Deposit.mint.owner\n function claimDeposit(IAsyncVault vault, address receiver, address controller) external payable;\n\n // --- Redeem ---\n /// @notice Check `IERC7887Deposit.cancelDepositRequest`.\n /// @dev This adds a mandatory prepayment for all the costs that will incur during the transaction.\n /// The caller must call `VaultRouter.estimate` to get estimates how much the deposit will cost.\n ///\n /// @param vault The vault where the deposit was initiated\n function cancelDepositRequest(IAsyncVault vault) external payable;\n\n /// @notice Check IERC7887Deposit.claimCancelDepositRequest\n ///\n /// @param vault Address of the vault\n /// @param receiver Check IERC7887Deposit.claimCancelDepositRequest.receiver\n /// @param controller Check IERC7887Deposit.claimCancelDepositRequest.controller\n function claimCancelDepositRequest(IAsyncVault vault, address receiver, address controller) external payable;\n\n // --- Redeem ---\n /// @notice Check `IERC7540Redeem.requestRedeem`.\n /// @dev This adds a mandatory prepayment for all the costs that will incur during the transaction.\n /// The caller must call `VaultRouter.estimate` to get estimates how much the deposit will cost.\n ///\n /// @param vault The vault to deposit into\n /// @param amount Check @param IERC7540Redeem.requestRedeem.shares\n /// @param controller Check @param IERC7540Redeem.requestRedeem.controller\n /// @param owner Check @param IERC7540Redeem.requestRedeem.owner\n function requestRedeem(IAsyncVault vault, uint256 amount, address controller, address owner) external payable;\n\n /// @notice Check IERC7575.withdraw\n /// @dev If the underlying vault asset is a wrapped one,\n /// `VaultRouter.unwrap` is called and the unwrapped\n /// asset is sent to the receiver\n /// @param vault Address of the vault\n /// @param receiver Check IERC7575.withdraw.receiver\n /// @param controller Check IERC7575.withdraw.owner\n function claimRedeem(IBaseVault vault, address receiver, address controller) external payable;\n\n /// @notice Check `IERC7887Redeem.cancelRedeemRequest`.\n /// @dev This adds a mandatory prepayment for all the costs that will incur during the transaction.\n /// The caller must call `VaultRouter.estimate` to get estimates how much the deposit will cost.\n ///\n /// @param vault The vault where the deposit was initiated\n function cancelRedeemRequest(IAsyncVault vault) external payable;\n\n /// @notice Check IERC7887Redeem.claimableCancelRedeemRequest\n ///\n /// @param vault Address of the vault\n /// @param receiver Check IERC7887Redeem.claimCancelRedeemRequest.receiver\n /// @param controller Check IERC7887Redeem.claimCancelRedeemRequest.controller\n function claimCancelRedeemRequest(IAsyncVault vault, address receiver, address controller) external payable;\n\n // --- ERC20 permit ---\n /// @notice Check IERC20.permit\n function permit(address asset, address spender, uint256 assets, uint256 deadline, uint8 v, bytes32 r, bytes32 s)\n external\n payable;\n\n // --- ERC20 wrapping ---\n /// @notice There are vault which underlying asset is actuall a wrapped one.\n ///\n /// @param wrapper The address of the wrapper\n /// @param amount Amount to be wrapped\n /// @param receiver Receiver of the wrapped tokens\n /// @param owner The address from which `amount` is taken from\n function wrap(address wrapper, uint256 amount, address receiver, address owner) external payable;\n\n /// @notice There are vault which underlying asset is actuall a wrapped one.\n /// @dev Wrapped tokens need to be held by the VaultRouter to be unwrapped.\n /// @param wrapper The address of the wrapper\n /// @param amount Amount to be wrapped\n /// @param receiver Receiver of the unwrapped tokens\n function unwrap(address wrapper, uint256 amount, address receiver) external payable;\n\n // --- View Methods ---\n /// @notice Check IPoolManager.getVault\n function getVault(PoolId poolId, ShareClassId scId, address asset) external view returns (address);\n\n /// @notice Check IGateway.estimate\n /// If the destination and source chain ID are the same, this will always return 0.\n /// @param centrifugeId destination chain\n function estimate(uint16 centrifugeId, bytes calldata payload) external view returns (uint256 amount);\n\n /// @notice Called to check if `user` has permissions on `vault` to execute requests\n ///\n /// @param vault Address of the `vault` the `user` wants to operate on\n /// @param user Address of the `user` that will operates on the `vault`\n /// @return Whether `user` has permissions to operate on `vault`\n function hasPermissions(IBaseVault vault, address user) external view returns (bool);\n\n /// @notice Returns whether the controller has called `enable()` for the given `vault`\n function isEnabled(IBaseVault vault, address controller) external view returns (bool);\n}\n" + }, + "src/vaults/interfaces/factories/IPoolEscrowFactory.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\n\nimport {IPoolEscrow} from \"src/vaults/interfaces/IEscrow.sol\";\n\ninterface IPoolEscrowProvider {\n /// @notice Returns the deterministic address of an escrow contract based on a given pool id wrapped into the\n /// corresponding interface.\n ///\n /// @dev Does not check, whether the escrow was already deployed.\n function escrow(PoolId poolId) external view returns (IPoolEscrow);\n}\n\ninterface IPoolEscrowFactory is IPoolEscrowProvider {\n event DeployPoolEscrow(PoolId indexed poolId, address indexed escrow);\n event File(bytes32 what, address data);\n\n error FileUnrecognizedParam();\n error EscrowAlreadyDeployed();\n\n /// @notice Deploys new escrow and returns it.\n /// @dev All share classes of a pool are represented by the same escrow contract.\n ///\n /// @param poolId Id of the pool this escrow is deployed for\n /// @return IPoolEscrow The the newly deployed escrow contract\n function newEscrow(PoolId poolId) external returns (IPoolEscrow);\n\n /// @notice Updates contract parameters of type address.\n function file(bytes32 what, address data) external;\n}\n" + }, + "src/vaults/interfaces/factories/ITokenFactory.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\n\ninterface ITokenFactory {\n /// @notice Used to deploy new share class tokens.\n /// @dev In order to have the same address on different EVMs `salt` should be used\n /// during creationg process.\n /// @param name Name of the new token.\n /// @param symbol Symbol of the new token.\n /// @param decimals Decimals of the new token.\n /// @param salt Salt used for deterministic deployments.\n /// @param tokenWards Address which can call methods behind authorized only.\n function newToken(\n string memory name,\n string memory symbol,\n uint8 decimals,\n bytes32 salt,\n address[] calldata tokenWards\n ) external returns (IShareToken);\n\n /// @notice Returns the predicted address (using CREATE2)\n function getAddress(uint8 decimals, bytes32 salt) external view returns (address);\n}\n" + }, + "src/vaults/interfaces/factories/IVaultFactory.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\nimport {IPoolEscrow} from \"src/vaults/interfaces/IEscrow.sol\";\nimport {IBaseVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\n\ninterface IVaultFactory {\n error UnsupportedTokenId();\n\n /// @notice Deploys new vault for `poolId`, `scId` and `asset`.\n ///\n /// @param poolId Id of the pool. Id is one of the already supported pools.\n /// @param scId Id of the share class token. Id is one of the already supported share class tokens.\n /// @param asset Address of the underlying asset that is getting deposited inside the pool.\n /// @param asset Token id of the underlying asset that is getting deposited inside the pool. I.e. zero if asset\n /// corresponds to ERC20 or non-zero if asset corresponds to ERC6909.\n /// @param token Address of the share class token that is getting issues against the deposited asset.\n /// @param wards_ Address which can call methods behind authorized only.\n function newVault(\n PoolId poolId,\n ShareClassId scId,\n address asset,\n uint256 tokenId,\n IShareToken token,\n address[] calldata wards_\n ) external returns (IBaseVault);\n}\n" + }, + "src/vaults/interfaces/investments/IAsyncDepositManager.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IDepositManager} from \"src/vaults/interfaces/investments/IDepositManager.sol\";\nimport {IBaseVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\n\ninterface IAsyncDepositManager is IDepositManager {\n /// @notice Requests assets deposit. Vaults have to request investments from Centrifuge before\n /// shares can be minted. The deposit requests are added to the order book\n /// on the corresponding CP instance. Once the next epoch is executed on the corresponding CP instance,\n /// vaults can\n /// proceed with share payouts in case the order got fulfilled.\n /// @dev The assets required to fulfill the deposit request have to be locked and are transferred from the\n /// owner to the escrow, even though the share payout can only happen after epoch execution.\n /// The receiver becomes the owner of deposit request fulfillment.\n /// @param source Deprecated\n function requestDeposit(IBaseVault vault, uint256 assets, address receiver, address owner, address source)\n external\n returns (bool);\n\n /// @notice Requests the cancellation of a pending deposit request. Vaults have to request the\n /// cancellation of outstanding requests from Centrifuge before actual assets can be unlocked and\n /// transferred\n /// to the owner.\n /// While users have outstanding cancellation requests no new deposit requests can be submitted.\n /// Once the next epoch is executed on the corresponding CP instance, vaults can proceed with asset payouts\n /// if orders could be cancelled successfully.\n /// @dev The cancellation request might fail in case the pending deposit order already got fulfilled on\n /// Centrifuge.\n /// @param source Deprecated\n function cancelDepositRequest(IBaseVault vault, address owner, address source) external;\n\n /// @notice Processes owner's deposit request cancellation after the epoch has been executed on the corresponding CP\n /// instance and the\n /// deposit order cancellation has been successfully processed (partial fulfillment possible).\n /// Assets are transferred from the escrow to the receiver.\n /// @dev The assets required to fulfill the claim have already been reserved for the owner in escrow on\n /// fulfillCancelDepositRequest.\n function claimCancelDepositRequest(IBaseVault vault, address receiver, address owner)\n external\n returns (uint256 assets);\n\n /// @notice Indicates whether a user has pending deposit requests and returns the total deposit request asset\n /// request value.\n function pendingDepositRequest(IBaseVault vault, address user) external view returns (uint256 assets);\n\n /// @notice Indicates whether a user has pending deposit request cancellations.\n function pendingCancelDepositRequest(IBaseVault vault, address user) external view returns (bool isPending);\n\n /// @notice Indicates whether a user has claimable deposit request cancellation and returns the total claim\n /// value in assets.\n function claimableCancelDepositRequest(IBaseVault vault, address user) external view returns (uint256 assets);\n}\n" + }, + "src/vaults/interfaces/investments/IAsyncRedeemManager.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IRedeemManager} from \"src/vaults/interfaces/investments/IRedeemManager.sol\";\nimport {IBaseVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\n\ninterface IAsyncRedeemManager is IRedeemManager {\n /// @notice Requests share redemption. Vaults have to request redemptions\n /// from Centrifuge before actual asset payouts can be done. The redemption\n /// requests are added to the order book on the corresponding CP instance. Once the next epoch is\n /// executed on the corresponding CP instance, vaults can proceed with asset payouts\n /// in case the order got fulfilled.\n /// @dev The shares required to fulfill the redemption request have to be locked and are transferred from the\n /// owner to the escrow, even though the asset payout can only happen after epoch execution.\n /// The receiver becomes the owner of redeem request fulfillment.\n /// @param source Deprecated\n function requestRedeem(IBaseVault vault, uint256 shares, address receiver, address owner, address source)\n external\n returns (bool);\n\n /// @notice Requests the cancellation of an pending redeem request. Vaults have to request the\n /// cancellation of outstanding requests from Centrifuge before actual shares can be unlocked and\n /// transferred to the owner.\n /// While users have outstanding cancellation requests no new redeem requests can be submitted (exception:\n /// trigger through governance).\n /// Once the next epoch is executed on the corresponding CP instance, vaults can proceed with share payouts\n /// if the orders could be cancelled successfully.\n /// @dev The cancellation request might fail in case the pending redeem order already got fulfilled on\n /// Centrifuge.\n function cancelRedeemRequest(IBaseVault vault, address owner, address source) external;\n\n /// @notice Processes owner's redeem request cancellation after the epoch has been executed on the corresponding CP\n /// instance and the\n /// redeem order cancellation has been successfully processed (partial fulfillment possible).\n /// Shares are transferred from the escrow to the receiver.\n /// @dev The shares required to fulfill the claim have already been reserved for the owner in escrow on\n /// fulfillCancelRedeemRequest.\n /// Receiver has to pass all the share token restrictions in order to receive the shares.\n function claimCancelRedeemRequest(IBaseVault vault, address receiver, address owner)\n external\n returns (uint256 shares);\n\n /// @notice Indicates whether a user has pending redeem requests and returns the total share request value.\n function pendingRedeemRequest(IBaseVault vault, address user) external view returns (uint256 shares);\n\n /// @notice Indicates whether a user has pending redeem request cancellations.\n function pendingCancelRedeemRequest(IBaseVault vault, address user) external view returns (bool isPending);\n\n /// @notice Indicates whether a user has claimable redeem request cancellation and returns the total claim\n /// value in shares.\n function claimableCancelRedeemRequest(IBaseVault vault, address user) external view returns (uint256 shares);\n}\n" + }, + "src/vaults/interfaces/investments/IAsyncRequestManager.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IRequestManagerGatewayHandler} from \"src/common/interfaces/IGatewayHandlers.sol\";\n\nimport {IAsyncDepositManager} from \"src/vaults/interfaces/investments/IAsyncDepositManager.sol\";\nimport {IAsyncRedeemManager} from \"src/vaults/interfaces/investments/IAsyncRedeemManager.sol\";\nimport {IBaseVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\n\n/// @dev Vault requests and deposit/redeem bookkeeping per user\nstruct AsyncInvestmentState {\n /// @dev Shares that can be claimed using `mint()`\n uint128 maxMint;\n /// @dev Assets that can be claimed using `withdraw()`\n uint128 maxWithdraw;\n /// @dev Weighted average price of deposits, used to convert maxMint to maxDeposit\n /// @dev Represents priceAssetPerShare, i.e. ASSET_UNIT/SHARE_UNIT\n uint256 depositPrice;\n /// @dev Weighted average price of redemptions, used to convert maxWithdraw to maxRedeem\n /// @dev Represents priceAssetPerShare, i.e. ASSET_UNIT/SHARE_UNIT\n uint256 redeemPrice;\n /// @dev Remaining deposit request in assets\n uint128 pendingDepositRequest;\n /// @dev Remaining redeem request in shares\n uint128 pendingRedeemRequest;\n /// @dev Assets that can be claimed using `claimCancelDepositRequest()`\n uint128 claimableCancelDepositRequest;\n /// @dev Shares that can be claimed using `claimCancelRedeemRequest()`\n uint128 claimableCancelRedeemRequest;\n /// @dev Indicates whether the depositRequest was requested to be cancelled\n bool pendingCancelDepositRequest;\n /// @dev Indicates whether the redeemRequest was requested to be cancelled\n bool pendingCancelRedeemRequest;\n}\n\ninterface IAsyncRequestManager is IAsyncDepositManager, IAsyncRedeemManager, IRequestManagerGatewayHandler {\n error ZeroAmountNotAllowed();\n error TransferNotAllowed();\n error CancellationIsPending();\n error NoPendingRequest();\n error ShareTokenAmountIsZero();\n error FailedRedeemRequest();\n error ExceedsDepositLimits();\n error ShareTokenTransferFailed();\n error ExceedsMaxRedeem();\n error ExceedsRedeemLimits();\n\n /// @notice Returns the investment state\n function investments(IBaseVault vaultAddr, address investor)\n external\n view\n returns (\n uint128 maxMint,\n uint128 maxWithdraw,\n uint256 depositPrice,\n uint256 redeemPrice,\n uint128 pendingDepositRequest,\n uint128 pendingRedeemRequest,\n uint128 claimableCancelDepositRequest,\n uint128 claimableCancelRedeemRequest,\n bool pendingCancelDepositRequest,\n bool pendingCancelRedeemRequest\n );\n}\n" + }, + "src/vaults/interfaces/investments/IBaseRequestManager.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\n\nimport {IPoolManager} from \"src/vaults/interfaces/IPoolManager.sol\";\nimport {IBaseVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\nimport {IPoolEscrow, IEscrow} from \"src/vaults/interfaces/IEscrow.sol\";\n\ninterface IBaseRequestManager {\n // --- Events ---\n event File(bytes32 indexed what, address data);\n\n error FileUnrecognizedParam();\n error SenderNotVault();\n error AssetNotAllowed();\n error ExceedsMaxDeposit();\n error AssetMismatch();\n error VaultAlreadyExists();\n error VaultDoesNotExist();\n\n /// @notice Updates contract parameters of type address.\n /// @param what The bytes32 representation of 'gateway' or 'poolManager'.\n /// @param data The new contract address.\n function file(bytes32 what, address data) external;\n\n /// @notice Converts the assets value to share decimals.\n function convertToShares(IBaseVault vault, uint256 _assets) external view returns (uint256 shares);\n\n /// @notice Converts the shares value to assets decimals.\n function convertToAssets(IBaseVault vault, uint256 _shares) external view returns (uint256 assets);\n\n /// @notice Returns the timestamp of the last share price update for a vaultAddr.\n function priceLastUpdated(IBaseVault vault) external view returns (uint64 lastUpdated);\n\n /// @notice Returns the PoolManager contract address.\n function poolManager() external view returns (IPoolManager poolManager);\n\n /// @notice The global escrow used for funds that are not yet free to be used for a specific pool\n function globalEscrow() external view returns (IEscrow escrow);\n\n /// @notice Escrow per pool. Funds are associated to a specific pool\n function poolEscrow(PoolId poolId) external view returns (IPoolEscrow);\n\n /// @notice Adds new vault for `poolId`, `scId` and `asset`.\n function addVault(PoolId poolId, ShareClassId scId, IBaseVault vault, address asset, AssetId assetId) external;\n\n /// @notice Removes `vault` from `who`'s authorized callers\n function removeVault(PoolId poolId, ShareClassId scId, IBaseVault vault, address asset, AssetId assetId) external;\n\n /// @notice Returns the address of the vault for a given pool, share class and asset\n function vaultByAssetId(PoolId poolId, ShareClassId scId, AssetId assetId)\n external\n view\n returns (IBaseVault vault);\n}\n" + }, + "src/vaults/interfaces/investments/IDepositManager.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IBaseRequestManager} from \"src/vaults/interfaces/investments/IBaseRequestManager.sol\";\nimport {IBaseVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\n\ninterface IDepositManager is IBaseRequestManager {\n /// @notice Processes owner's asset deposit after the epoch has been executed on the corresponding CP instance and\n /// the deposit order\n /// has been successfully processed (partial fulfillment possible).\n /// Shares are transferred from the escrow to the receiver. Amount of shares is computed based of the amount\n /// of assets and the owner's share price.\n /// @dev The assets required to fulfill the deposit are already locked in escrow upon calling requestDeposit.\n /// The shares required to fulfill the deposit have already been minted and transferred to the escrow on\n /// fulfillDepositRequest.\n /// Receiver has to pass all the share token restrictions in order to receive the shares.\n function deposit(IBaseVault vault, uint256 assets, address receiver, address owner)\n external\n returns (uint256 shares);\n\n /// @notice Processes owner's share mint after the epoch has been executed on the corresponding CP instance and the\n /// deposit order has\n /// been successfully processed (partial fulfillment possible).\n /// Shares are transferred from the escrow to the receiver. Amount of assets is computed based of the amount\n /// of shares and the owner's share price.\n /// @dev The assets required to fulfill the mint are already locked in escrow upon calling requestDeposit.\n /// The shares required to fulfill the mint have already been minted and transferred to the escrow on\n /// fulfillDepositRequest.\n /// Receiver has to pass all the share token restrictions in order to receive the shares.\n function mint(IBaseVault vault, uint256 shares, address receiver, address owner)\n external\n returns (uint256 assets);\n\n /// @notice Returns the max amount of assets based on the unclaimed amount of shares after at least one successful\n /// deposit order fulfillment on the corresponding CP instance.\n function maxDeposit(IBaseVault vault, address user) external view returns (uint256);\n\n /// @notice Returns the max amount of shares a user can claim after at least one successful deposit order\n /// fulfillment on the corresponding CP instance.\n function maxMint(IBaseVault vault, address user) external view returns (uint256 shares);\n}\n" + }, + "src/vaults/interfaces/investments/IRedeemManager.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IBaseRequestManager} from \"src/vaults/interfaces/investments/IBaseRequestManager.sol\";\nimport {IBaseVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\n\ninterface IRedeemManager is IBaseRequestManager {\n event TriggerRedeemRequest(\n uint64 indexed poolId,\n bytes16 indexed scId,\n address user,\n address indexed asset,\n uint256 tokenId,\n uint128 shares\n );\n\n /// @notice Processes owner's share redemption after the epoch has been executed on the corresponding CP instance\n /// and the redeem order\n /// has been successfully processed (partial fulfillment possible).\n /// Assets are transferred from the escrow to the receiver. Amount of assets is computed based of the amount\n /// of shares and the owner's share price.\n /// @dev The shares required to fulfill the redemption were already locked in escrow on requestRedeem and burned\n /// on fulfillRedeemRequest.\n /// The assets required to fulfill the redemption have already been reserved in escrow on\n /// fulfillRedeemtRequest.\n function redeem(IBaseVault vault, uint256 shares, address receiver, address owner)\n external\n returns (uint256 assets);\n\n /// @notice Processes owner's asset withdrawal after the epoch has been executed on the corresponding CP instance\n /// and the redeem order\n /// has been successfully processed (partial fulfillment possible).\n /// Assets are transferred from the escrow to the receiver. Amount of shares is computed based of the amount\n /// of shares and the owner's share price.\n /// @dev The shares required to fulfill the withdrawal were already locked in escrow on requestRedeem and burned\n /// on fulfillRedeemRequest.\n /// The assets required to fulfill the withdrawal have already been reserved in escrow on\n /// fulfillRedeemtRequest.\n function withdraw(IBaseVault vault, uint256 assets, address receiver, address owner)\n external\n returns (uint256 shares);\n\n /// @notice Returns the max amount of shares based on the unclaimed number of assets after at least one successful\n /// redeem order fulfillment on the corresponding CP instance.\n function maxRedeem(IBaseVault vault, address user) external view returns (uint256 shares);\n\n /// @notice Returns the max amount of assets a user can claim after at least one successful redeem order fulfillment\n /// on the corresponding CP instance.\n function maxWithdraw(IBaseVault vault, address user) external view returns (uint256 assets);\n}\n" + }, + "src/vaults/interfaces/investments/ISyncDepositManager.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IDepositManager} from \"src/vaults/interfaces/investments/IDepositManager.sol\";\nimport {IBaseVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\n\ninterface ISyncDepositManager is IDepositManager {\n function previewDeposit(IBaseVault vault, address sender, uint256 assets) external view returns (uint256);\n function previewMint(IBaseVault vault, address sender, uint256 shares) external view returns (uint256);\n}\n" + }, + "src/vaults/interfaces/investments/ISyncRequestManager.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {D18} from \"src/misc/types/D18.sol\";\n\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nimport {IUpdateContract} from \"src/vaults/interfaces/IUpdateContract.sol\";\nimport {ISyncDepositManager} from \"src/vaults/interfaces/investments/ISyncDepositManager.sol\";\n\n/// @dev Solely used locally as protection against stack-too-deep\nstruct Prices {\n /// @dev Price of 1 asset unit per share unit\n D18 assetPerShare;\n /// @dev Price of 1 pool unit per asset unit\n D18 poolPerAsset;\n /// @dev Price of 1 pool unit per share unit\n D18 poolPerShare;\n}\n\ninterface ISyncDepositValuation {\n /// @notice Returns the pool price per share for a given pool and share class, asset, and asset id.\n // The provided price is defined as POOL_UNIT/SHARE_UNIT.\n ///\n /// @param poolId The pool id\n /// @param scId The share class id\n /// @return price The pool price per share\n function pricePoolPerShare(PoolId poolId, ShareClassId scId) external view returns (D18 price);\n}\n\ninterface ISyncRequestManager is ISyncDepositManager, ISyncDepositValuation, IUpdateContract {\n event SetValuation(PoolId indexed poolId, ShareClassId indexed scId, address valuation);\n event SetMaxReserve(\n PoolId indexed poolId, ShareClassId indexed scId, address asset, uint256 tokenId, uint128 maxReserve\n );\n\n error ExceedsMaxMint();\n error ShareTokenDoesNotExist();\n error SecondaryManagerDoesNotExist();\n\n /// @notice Sets the valuation for a specific pool and share class.\n ///\n /// @param poolId The id of the pool\n /// @param scId The id of the share class\n /// @param valuation The address of the valuation contract\n function setValuation(PoolId poolId, ShareClassId scId, address valuation) external;\n\n /// @notice Sets the max reserve for a specific pool, share class and asset.\n ///\n /// @param poolId The id of the pool\n /// @param scId The id of the share class\n /// @param asset The address of the asset\n /// @param tokenId The asset token id, i.e. 0 for ERC20, or the token id for ERC6909\n /// @param maxReserve The amount of maximum reserve\n function setMaxReserve(PoolId poolId, ShareClassId scId, address asset, uint256 tokenId, uint128 maxReserve)\n external;\n\n /// @notice Returns the all three prices for a given pool, share class, asset, and asset id.\n ///\n /// @param poolId The pool id\n /// @param scId The share class id\n /// @param assetId The asset id corresponding to the asset and tokenId\n /// @return priceData The asset price per share, pool price per asset, and pool price per share\n function prices(PoolId poolId, ShareClassId scId, AssetId assetId)\n external\n view\n returns (Prices memory priceData);\n}\n" + }, + "src/vaults/interfaces/token/IShareToken.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IERC20Metadata} from \"src/misc/interfaces/IERC20.sol\";\nimport {IERC7575Share} from \"src/misc/interfaces/IERC7575.sol\";\n\ninterface IERC1404 {\n /// @notice Detects if a transfer will be reverted and if so returns an appropriate reference code\n /// @param from Sending address\n /// @param to Receiving address\n /// @param value Amount of tokens being transferred\n /// @return Code by which to reference message for rejection reasoning\n /// @dev Overwrite with your custom transfer restriction logic\n function detectTransferRestriction(address from, address to, uint256 value) external view returns (uint8);\n\n /// @notice Returns a human-readable message for a given restriction code\n /// @param restrictionCode Identifier for looking up a message\n /// @return Text showing the restriction's reasoning\n /// @dev Overwrite with your custom message and restrictionCode handling\n function messageForTransferRestriction(uint8 restrictionCode) external view returns (string memory);\n}\n\ninterface IShareToken is IERC20Metadata, IERC7575Share, IERC1404 {\n // --- Events ---\n event File(bytes32 indexed what, address data);\n event SetHookData(address indexed user, bytes16 data);\n\n // --- Errors ---\n error NotAuthorizedOrHook();\n error ExceedsMaxSupply();\n error RestrictionsFailed();\n\n struct Balance {\n /// @dev The user balance is limited to uint128. This is safe because the decimals are limited to 18,\n /// thus the max balance is 2^128-1 / 10**18 = 3.40 * 10**20. This is also enforced on mint.\n uint128 amount;\n /// @dev There are 16 bytes that are used to store hook data (e.g. restrictions for users).\n bytes16 hookData;\n }\n\n // --- Administration ---\n /// @notice returns the hook that transfers perform callbacks to\n /// @dev MUST comply to `IHook` interface\n function hook() external view returns (address);\n\n /// @notice Updates a contract parameter\n /// @param what Accepts a bytes32 representation of 'name', 'symbol'\n function file(bytes32 what, string memory data) external;\n\n /// @notice Updates a contract parameter\n /// @param what Accepts a bytes32 representation of 'hook'\n function file(bytes32 what, address data) external;\n\n /// @notice updates the vault for a given `asset`\n function updateVault(address asset, address vault_) external;\n\n // --- ERC20 overrides ---\n /// @notice returns the 16 byte hook data of the given `user`.\n /// @dev Stored in the 128 most significant bits of the user balance\n function hookDataOf(address user) external view returns (bytes16);\n\n /// @notice update the 16 byte hook data of the given `user`\n function setHookData(address user, bytes16 hookData) external;\n\n /// @notice Function to mint tokens\n function mint(address user, uint256 value) external;\n\n /// @notice Function to burn tokens\n function burn(address user, uint256 value) external;\n\n /// @notice Checks if the tokens can be transferred given the input values\n function checkTransferRestriction(address from, address to, uint256 value) external view returns (bool);\n\n /// @notice Performs an authorized transfer, with `sender` as the given sender.\n /// @dev Requires allowance if `sender` != `from`\n function authTransferFrom(address sender, address from, address to, uint256 amount) external returns (bool);\n}\n" + }, + "src/vaults/legacy/LegacyVaultAdapter.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nimport {ILegacyVault} from \"src/vaults/legacy/interfaces/ILegacyVault.sol\";\nimport {IInvestmentManager} from \"src/vaults/legacy/interfaces/IInvestmentManager.sol\";\nimport {ILegacyVaultAdapter} from \"src/vaults/legacy/interfaces/ILegacyVaultAdapter.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\nimport {AsyncVault} from \"src/vaults/AsyncVault.sol\";\nimport {IAsyncRequestManager} from \"src/vaults/interfaces/investments/IAsyncRequestManager.sol\";\nimport {BaseAsyncRedeemVault, IAsyncRedeemVault} from \"src/vaults/BaseVaults.sol\";\n\n/// @title LegacyVaultAdapter\n/// @notice An adapter connecting legacy ERC-7540 vaults from Centrifuge V2 to Centrifuge V3.\n///\n/// @dev This adapter acts as an `IInvestmentManager` for a single legacy `ILegacyVault` vault from Centrifuge V2.\n/// At the same time it acts like a new `IAsyncVault` for the `IAsyncRequestManager` manager of Centrifuge V3.\n/// The adapter needs to be deployed per legacy vault and allows a seamless interaction between Centrifuge V2\n/// vaults and Centrifuge V3 infrastructure. Thereby, allowing to migrate existing vaults to the new system.\ncontract LegacyVaultAdapter is AsyncVault, ILegacyVaultAdapter, IInvestmentManager {\n uint64 public immutable legacyPoolId;\n bytes16 public immutable legacyTrancheId;\n ILegacyVault public immutable legacyVault;\n\n constructor(\n ILegacyVault legacyVault_,\n PoolId poolId,\n uint64 legacyPoolId_,\n ShareClassId scId,\n bytes16 legacyTrancheId_,\n address asset,\n IShareToken token,\n address root,\n IAsyncRequestManager manager\n ) AsyncVault(poolId, scId, asset, token, root, manager) {\n require(legacyVault_.poolId() == legacyPoolId_, NotLegacyPoolId(legacyPoolId_, legacyVault_.poolId()));\n require(\n legacyVault_.trancheId() == legacyTrancheId_, NotLegacyTrancheId(legacyTrancheId_, legacyVault_.trancheId())\n );\n require(legacyVault_.asset() == asset, NotLegacyAsset(asset, legacyVault_.asset()));\n require(legacyVault_.share() == address(token), NotLegacyShare(address(token), legacyVault_.share()));\n\n legacyPoolId = legacyPoolId_;\n legacyTrancheId = legacyTrancheId_;\n legacyVault = legacyVault_;\n }\n\n /// @dev Check if the msg.sender is the legacy vault\n modifier legacy() {\n require(msg.sender == address(legacyVault), NotLegacyVault(msg.sender, address(legacyVault)));\n _;\n }\n\n //----------------------------------------------------------------------------------------------\n // IInvestmentManager handlers\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IInvestmentManager\n function requestDeposit(address, /* vault */ uint256 assets, address receiver, address owner, address source)\n public\n legacy\n returns (bool)\n {\n return asyncManager().requestDeposit(this, assets, receiver, owner, source);\n }\n\n /// @inheritdoc IInvestmentManager\n function requestRedeem(address, /* vault */ uint256 shares, address receiver, address owner, address source)\n public\n legacy\n returns (bool)\n {\n return asyncManager().requestRedeem(this, shares, receiver, owner, source);\n }\n\n /// @inheritdoc IInvestmentManager\n function cancelDepositRequest(address, /* vault */ address owner, address source) public legacy {\n return asyncManager().cancelDepositRequest(this, owner, source);\n }\n\n /// @inheritdoc IInvestmentManager\n function cancelRedeemRequest(address, /* vault */ address owner, address source) public legacy {\n return asyncManager().cancelRedeemRequest(this, owner, source);\n }\n\n //----------------------------------------------------------------------------------------------\n // IInvestmentManager view methods\n //----------------------------------------------------------------------------------------------\n\n function escrow() public view returns (address) {\n return address(manager.globalEscrow());\n }\n\n /// @inheritdoc IInvestmentManager\n function convertToShares(address, /* vault */ uint256 _assets) public view returns (uint256 shares) {\n shares = asyncManager().convertToShares(this, _assets);\n }\n\n /// @inheritdoc IInvestmentManager\n function convertToAssets(address, /* vault */ uint256 _shares) public view returns (uint256 assets) {\n assets = asyncManager().convertToAssets(this, _shares);\n }\n\n /// @inheritdoc IInvestmentManager\n function maxDeposit(address, /* vault */ address user) public view returns (uint256 assets) {\n assets = asyncManager().maxDeposit(this, user);\n }\n\n /// @inheritdoc IInvestmentManager\n function maxMint(address, /* vault */ address user) public view returns (uint256 shares) {\n shares = asyncManager().maxMint(this, user);\n }\n\n /// @inheritdoc IInvestmentManager\n function maxWithdraw(address, /* vault */ address user) public view returns (uint256 assets) {\n assets = asyncManager().maxWithdraw(this, user);\n }\n\n /// @inheritdoc IInvestmentManager\n function maxRedeem(address, /* vault */ address user) public view returns (uint256 shares) {\n shares = asyncManager().maxRedeem(this, user);\n }\n\n /// @inheritdoc IInvestmentManager\n function pendingDepositRequest(address, /* vault */ address user) public view returns (uint256 assets) {\n assets = asyncManager().pendingDepositRequest(this, user);\n }\n\n /// @inheritdoc IInvestmentManager\n function pendingRedeemRequest(address, /* vault */ address user) public view returns (uint256 shares) {\n shares = asyncManager().pendingRedeemRequest(this, user);\n }\n\n /// @inheritdoc IInvestmentManager\n function pendingCancelDepositRequest(address, /* vault */ address user) public view returns (bool isPending) {\n isPending = asyncManager().pendingCancelDepositRequest(this, user);\n }\n\n /// @inheritdoc IInvestmentManager\n function pendingCancelRedeemRequest(address, /* vault */ address user) public view returns (bool isPending) {\n isPending = asyncManager().pendingCancelRedeemRequest(this, user);\n }\n\n /// @inheritdoc IInvestmentManager\n function claimableCancelDepositRequest(address, /* vault */ address user) public view returns (uint256 assets) {\n assets = asyncManager().claimableCancelDepositRequest(this, user);\n }\n\n /// @inheritdoc IInvestmentManager\n function claimableCancelRedeemRequest(address, /* vault */ address user) public view returns (uint256 shares) {\n shares = asyncManager().claimableCancelRedeemRequest(this, user);\n }\n\n /// @inheritdoc IInvestmentManager\n function priceLastUpdated(address /* vault */ ) public view returns (uint64 lastUpdated) {\n lastUpdated = manager.priceLastUpdated(this);\n }\n\n //----------------------------------------------------------------------------------------------\n // IInvestmentManager vault claim methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IInvestmentManager\n function deposit(address, /* vault */ uint256 assets, address receiver, address owner)\n public\n legacy\n returns (uint256 shares)\n {\n shares = asyncManager().deposit(this, assets, receiver, owner);\n }\n\n /// @inheritdoc IInvestmentManager\n function mint(address, /* vault */ uint256 shares, address receiver, address owner)\n public\n legacy\n returns (uint256 assets)\n {\n assets = asyncManager().mint(this, shares, receiver, owner);\n }\n\n /// @inheritdoc IInvestmentManager\n function redeem(address, /* vault */ uint256 shares, address receiver, address owner)\n public\n legacy\n returns (uint256 assets)\n {\n assets = asyncManager().redeem(this, shares, receiver, owner);\n }\n\n /// @inheritdoc IInvestmentManager\n function withdraw(address, /* vault */ uint256 assets, address receiver, address owner)\n public\n legacy\n returns (uint256 shares)\n {\n shares = asyncManager().withdraw(this, assets, receiver, owner);\n }\n\n /// @inheritdoc IInvestmentManager\n function claimCancelDepositRequest(address, /* vault */ address receiver, address owner)\n public\n legacy\n returns (uint256 assets)\n {\n assets = asyncManager().claimCancelDepositRequest(this, receiver, owner);\n }\n\n /// @inheritdoc IInvestmentManager\n function claimCancelRedeemRequest(address, /* vault */ address receiver, address owner)\n public\n legacy\n returns (uint256 shares)\n {\n shares = asyncManager().claimCancelRedeemRequest(this, receiver, owner);\n }\n\n //----------------------------------------------------------------------------------------------\n // Event emitters\n //----------------------------------------------------------------------------------------------\n\n function onDepositClaimable(address controller, uint256 assets, uint256 shares) public override auth {\n legacyVault.onDepositClaimable(controller, assets, shares);\n }\n\n function onCancelDepositClaimable(address controller, uint256 assets) public override auth {\n legacyVault.onCancelDepositClaimable(controller, assets);\n }\n\n function onRedeemRequest(address controller, address owner, uint256 shares)\n public\n override(BaseAsyncRedeemVault, IAsyncRedeemVault)\n auth\n {\n legacyVault.onRedeemRequest(controller, owner, shares);\n }\n\n function onRedeemClaimable(address controller, uint256 assets, uint256 shares)\n public\n override(BaseAsyncRedeemVault, IAsyncRedeemVault)\n auth\n {\n legacyVault.onRedeemClaimable(controller, assets, shares);\n }\n\n function onCancelRedeemClaimable(address controller, uint256 shares)\n public\n override(BaseAsyncRedeemVault, IAsyncRedeemVault)\n auth\n {\n legacyVault.onCancelRedeemClaimable(controller, shares);\n }\n}\n" + }, + "src/vaults/legacy/interfaces/IInvestmentManager.sol": { + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.5.0;\n\n/// @notice A stripped down version of the Centrifuge V2 investment manager.\n///\n/// @dev This interface is needed to ensure adapters for legacy vaults are provided with the expected interface.\ninterface IInvestmentManager {\n /// @notice Documentation see Centrifuge V2 repository.\n function escrow() external view returns (address);\n\n // --- Outgoing message handling ---\n /// @notice Documentation see Centrifuge V2 repository.\n function requestDeposit(address vault, uint256 assets, address receiver, address owner, address source)\n external\n returns (bool);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function requestRedeem(address vault, uint256 shares, address receiver, address, /* owner */ address source)\n external\n returns (bool);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function cancelDepositRequest(address vault, address owner, address source) external;\n\n /// @notice Documentation see Centrifuge V2 repository.\n function cancelRedeemRequest(address vault, address owner, address source) external;\n\n // --- View functions ---\n /// @notice Documentation see Centrifuge V2 repository.\n function convertToShares(address vault, uint256 _assets) external view returns (uint256 shares);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function convertToAssets(address vault, uint256 _shares) external view returns (uint256 assets);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function maxDeposit(address vault, address user) external view returns (uint256);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function maxMint(address vault, address user) external view returns (uint256 shares);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function maxWithdraw(address vault, address user) external view returns (uint256 assets);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function maxRedeem(address vault, address user) external view returns (uint256 shares);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function pendingDepositRequest(address vault, address user) external view returns (uint256 assets);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function pendingRedeemRequest(address vault, address user) external view returns (uint256 shares);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function pendingCancelDepositRequest(address vault, address user) external view returns (bool isPending);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function pendingCancelRedeemRequest(address vault, address user) external view returns (bool isPending);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function claimableCancelDepositRequest(address vault, address user) external view returns (uint256 assets);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function claimableCancelRedeemRequest(address vault, address user) external view returns (uint256 shares);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function priceLastUpdated(address vault) external view returns (uint64 lastUpdated);\n\n // --- Vault claim functions ---\n /// @notice Documentation see Centrifuge V2 repository.\n function deposit(address vault, uint256 assets, address receiver, address owner)\n external\n returns (uint256 shares);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function mint(address vault, uint256 shares, address receiver, address owner) external returns (uint256 assets);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function redeem(address vault, uint256 shares, address receiver, address owner) external returns (uint256 assets);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function withdraw(address vault, uint256 assets, address receiver, address owner)\n external\n returns (uint256 shares);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function claimCancelDepositRequest(address vault, address receiver, address owner)\n external\n returns (uint256 assets);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function claimCancelRedeemRequest(address vault, address receiver, address owner)\n external\n returns (uint256 shares);\n}\n" + }, + "src/vaults/legacy/interfaces/ILegacyVault.sol": { + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.5.0;\n\n/// @notice A stripped down version of the Centrifuge V2 ERC-7540 vault.\n///\n/// @dev This interface is needed to ensure adapters for legacy vaults are provided with the expected interface.\ninterface ILegacyVault {\n /// @notice Documentation see Centrifuge V2 repository.\n function poolId() external view returns (uint64);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function trancheId() external view returns (bytes16);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function asset() external view returns (address);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function share() external view returns (address);\n\n /// @notice Callback when a redeem Request is triggered externally;\n function onRedeemRequest(address controller, address owner, uint256 shares) external;\n\n /// @notice Callback when a deposit Request becomes claimable\n function onDepositClaimable(address owner, uint256 assets, uint256 shares) external;\n\n /// @notice Callback when a redeem Request becomes claimable\n function onRedeemClaimable(address owner, uint256 assets, uint256 shares) external;\n\n /// @notice Callback when a claim deposit Request becomes claimable\n function onCancelDepositClaimable(address owner, uint256 assets) external;\n\n /// @notice Callback when a claim redeem Request becomes claimable\n function onCancelRedeemClaimable(address owner, uint256 shares) external;\n}\n" + }, + "src/vaults/legacy/interfaces/ILegacyVaultAdapter.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\ninterface ILegacyVaultAdapter {\n error NotLegacyVault(address sender, address legacyVault);\n error NotLegacyPoolId(uint64 providedPoolId, uint64 legacyPoolId);\n error NotLegacyTrancheId(bytes16 providedTrancheId, bytes16 legacyTrancheId);\n error NotLegacyAsset(address providedAsset, address legacyAsset);\n error NotLegacyShare(address providedShare, address legacyShare);\n}\n" + }, + "src/vaults/token/ShareToken.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {ERC20} from \"src/misc/ERC20.sol\";\nimport {IERC20, IERC20Metadata} from \"src/misc/interfaces/IERC20.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {IERC7575Share, IERC165} from \"src/misc/interfaces/IERC7575.sol\";\n\nimport {\n IHook,\n HookData,\n SUCCESS_CODE_ID,\n SUCCESS_MESSAGE,\n ERROR_CODE_ID,\n ERROR_MESSAGE\n} from \"src/common/interfaces/IHook.sol\";\nimport {IShareToken, IERC1404} from \"src/vaults/interfaces/token/IShareToken.sol\";\n\n/// @title Share Token\n/// @notice Extension of ERC20 + ERC1404,\n/// integrating an external hook optionally for ERC20 callbacks and ERC1404 checks.\ncontract ShareToken is ERC20, IShareToken {\n using MathLib for uint256;\n\n mapping(address => Balance) private balances;\n\n /// @inheritdoc IShareToken\n address public hook;\n\n /// @inheritdoc IERC7575Share\n mapping(address asset => address) public vault;\n\n constructor(uint8 decimals_) ERC20(decimals_) {}\n\n modifier authOrHook() {\n require(wards[msg.sender] == 1 || msg.sender == hook, NotAuthorizedOrHook());\n _;\n }\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IShareToken\n function file(bytes32 what, address data) external authOrHook {\n if (what == \"hook\") hook = data;\n else revert FileUnrecognizedParam();\n emit File(what, data);\n }\n\n /// @inheritdoc IShareToken\n function file(bytes32 what, string memory data) public override(ERC20, IShareToken) auth {\n super.file(what, data);\n }\n\n /// @inheritdoc IShareToken\n function updateVault(address asset, address vault_) external auth {\n vault[asset] = vault_;\n emit VaultUpdate(asset, vault_);\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-20 overrides\n //----------------------------------------------------------------------------------------------\n\n function _balanceOf(address user) internal view override returns (uint256) {\n return balances[user].amount;\n }\n\n function _setBalance(address user, uint256 value) internal override {\n balances[user].amount = value.toUint128();\n }\n\n /// @inheritdoc IShareToken\n function hookDataOf(address user) public view returns (bytes16) {\n return balances[user].hookData;\n }\n\n /// @inheritdoc IShareToken\n function setHookData(address user, bytes16 hookData) public authOrHook {\n balances[user].hookData = hookData;\n emit SetHookData(user, hookData);\n }\n\n /// @inheritdoc IERC20\n function transfer(address to, uint256 value) public override(ERC20, IERC20) returns (bool success) {\n success = super.transfer(to, value);\n _onTransfer(msg.sender, to, value);\n }\n\n /// @inheritdoc IERC20\n function transferFrom(address from, address to, uint256 value)\n public\n override(ERC20, IERC20)\n returns (bool success)\n {\n success = super.transferFrom(from, to, value);\n _onTransfer(from, to, value);\n }\n\n /// @inheritdoc IShareToken\n function mint(address to, uint256 value) public override(ERC20, IShareToken) {\n super.mint(to, value);\n require(totalSupply <= type(uint128).max, ExceedsMaxSupply());\n _onTransfer(address(0), to, value);\n }\n\n /// @inheritdoc IShareToken\n function burn(address from, uint256 value) public override(ERC20, IShareToken) {\n super.burn(from, value);\n _onTransfer(from, address(0), value);\n }\n\n function _onTransfer(address from, address to, uint256 value) internal {\n address hook_ = hook;\n require(\n hook_ == address(0)\n || IHook(hook_).onERC20Transfer(from, to, value, HookData(hookDataOf(from), hookDataOf(to)))\n == IHook.onERC20Transfer.selector,\n RestrictionsFailed()\n );\n }\n\n /// @inheritdoc IShareToken\n function authTransferFrom(address sender, address from, address to, uint256 value)\n public\n auth\n returns (bool success)\n {\n success = _transferFrom(sender, from, to, value);\n address hook_ = hook;\n if (hook_ != address(0)) {\n IHook(hook_).onERC20AuthTransfer(sender, from, to, value, HookData(hookDataOf(from), hookDataOf(to)));\n }\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-1404\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IShareToken\n function checkTransferRestriction(address from, address to, uint256 value) public view returns (bool) {\n return detectTransferRestriction(from, to, value) == SUCCESS_CODE_ID;\n }\n\n /// @inheritdoc IERC1404\n function detectTransferRestriction(address from, address to, uint256 value) public view returns (uint8) {\n address hook_ = hook;\n if (hook_ == address(0)) return SUCCESS_CODE_ID;\n return IHook(hook_).checkERC20Transfer(from, to, value, HookData(hookDataOf(from), hookDataOf(to)))\n ? SUCCESS_CODE_ID\n : ERROR_CODE_ID;\n }\n\n /// @inheritdoc IERC1404\n function messageForTransferRestriction(uint8 restrictionCode) external pure returns (string memory) {\n return restrictionCode == SUCCESS_CODE_ID ? SUCCESS_MESSAGE : ERROR_MESSAGE;\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-165\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC165\n function supportsInterface(bytes4 interfaceId) external pure override returns (bool) {\n return interfaceId == type(IERC7575Share).interfaceId || interfaceId == type(IERC165).interfaceId;\n }\n}\n" + } + }, + "settings": { + "remappings": [ + "forge-std/=lib/forge-std/src/", + "@chimera/=lib/chimera/src/", + "chimera/=lib/chimera/src/", + "ds-test/=lib/chimera/lib/forge-std/lib/ds-test/src/" + ], + "optimizer": { "enabled": true, "runs": 1 }, + "metadata": { + "useLiteralContent": false, + "bytecodeHash": "none", + "appendCBOR": true + }, + "outputSelection": { + "lib/forge-std/src/interfaces/IERC165.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/GasService.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/common/Gateway.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/Guardian.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/MessageDispatcher.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/MessageProcessor.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/Root.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/TokenRecoverer.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/adapters/AxelarAdapter.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/adapters/WormholeAdapter.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/interfaces/IAdapter.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/interfaces/IAxelarAdapter.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/interfaces/IGasService.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/interfaces/IGateway.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/interfaces/IGatewayHandlers.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/interfaces/IGatewaySenders.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/interfaces/IGuardian.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/interfaces/IGuardianActions.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/interfaces/IHook.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/interfaces/IMessageDispatcher.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/interfaces/IMessageHandler.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/interfaces/IMessageProcessor.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/interfaces/IMessageProperties.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/interfaces/IMessageSender.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/interfaces/IRoot.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/interfaces/ITokenRecoverer.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/interfaces/IWormholeAdapter.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/libraries/MessageLib.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/libraries/MessageProofLib.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/libraries/PricingLib.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/types/AccountId.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/types/AssetId.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/types/PoolId.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/common/types/ShareClassId.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/hooks/FreezeOnly.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/hooks/FullRestrictions.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/hooks/RedemptionRestrictions.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/hooks/interfaces/IFreezable.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/hooks/interfaces/IMemberlist.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/hub/Accounting.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/hub/Holdings.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/hub/Hub.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/hub/HubRegistry.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/hub/ShareClassManager.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/hub/interfaces/IAccounting.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/hub/interfaces/IHoldings.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/hub/interfaces/IHub.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/hub/interfaces/IHubRegistry.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/hub/interfaces/IShareClassManager.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/misc/Auth.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/misc/BaseValuation.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/misc/ERC20.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/misc/IdentityValuation.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/misc/Multicall.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/misc/Recoverable.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/misc/ReentrancyProtection.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/misc/interfaces/IAuth.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/misc/interfaces/IBaseValuation.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/misc/interfaces/IERC20.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/misc/interfaces/IERC6909.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/misc/interfaces/IERC7540.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/misc/interfaces/IERC7575.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/misc/interfaces/IERC7726.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/misc/interfaces/IIdentityValuation.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/misc/interfaces/IMulticall.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/misc/interfaces/IRecoverable.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/misc/libraries/ArrayLib.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/misc/libraries/BitmapLib.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/misc/libraries/BytesLib.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/misc/libraries/CastLib.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/misc/libraries/EIP712Lib.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/misc/libraries/MathLib.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/misc/libraries/SafeTransferLib.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/misc/libraries/SignatureLib.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/misc/libraries/StringLib.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/misc/libraries/TransientArrayLib.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/misc/libraries/TransientBytesLib.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/misc/libraries/TransientStorageLib.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/misc/types/D18.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/AsyncRequestManager.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/AsyncVault.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/BalanceSheet.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/BaseRequestManager.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/BaseVaults.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/Escrow.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/PoolManager.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/SyncDepositVault.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/SyncRequestManager.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/VaultRouter.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/factories/AsyncVaultFactory.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/factories/PoolEscrowFactory.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/factories/SyncDepositVaultFactory.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/factories/TokenFactory.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/interfaces/IBalanceSheet.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/interfaces/IBaseVaults.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/interfaces/IEscrow.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/interfaces/IPoolManager.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/interfaces/IUpdateContract.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/interfaces/IVaultRouter.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/interfaces/factories/IPoolEscrowFactory.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/interfaces/factories/ITokenFactory.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/interfaces/factories/IVaultFactory.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/interfaces/investments/IAsyncDepositManager.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/interfaces/investments/IAsyncRedeemManager.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/interfaces/investments/IAsyncRequestManager.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/interfaces/investments/IBaseRequestManager.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/interfaces/investments/IDepositManager.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/interfaces/investments/IRedeemManager.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/interfaces/investments/ISyncDepositManager.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/interfaces/investments/ISyncRequestManager.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/interfaces/token/IShareToken.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/legacy/LegacyVaultAdapter.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/legacy/interfaces/IInvestmentManager.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/legacy/interfaces/ILegacyVault.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/legacy/interfaces/ILegacyVaultAdapter.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + }, + "src/vaults/token/ShareToken.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata"] + } + }, + "evmVersion": "cancun", + "viaIR": true, + "libraries": {} + } +} diff --git a/crates/resolc/src/tests/data/standard_json/pvm_codegen_per_file.json b/crates/resolc/src/tests/data/standard_json/pvm_codegen_per_file.json new file mode 100644 index 0000000..db7eed7 --- /dev/null +++ b/crates/resolc/src/tests/data/standard_json/pvm_codegen_per_file.json @@ -0,0 +1,720 @@ +{ + "language": "Solidity", + "sources": { + "lib/forge-std/src/interfaces/IERC165.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.6.2;\n\ninterface IERC165 {\n /// @notice Query if a contract implements an interface\n /// @param interfaceID The interface identifier, as specified in ERC-165\n /// @dev Interface identification is specified in ERC-165. This function\n /// uses less than 30,000 gas.\n /// @return `true` if the contract implements `interfaceID` and\n /// `interfaceID` is not 0xffffffff, `false` otherwise\n function supportsInterface(bytes4 interfaceID) external view returns (bool);\n}\n" + }, + "src/common/GasService.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IGasService} from \"src/common/interfaces/IGasService.sol\";\n\n/// @title GasService\n/// @notice This is a utility contract used to determine the execution gas limit\n/// for a payload being sent across all supported adapters.\ncontract GasService is IGasService {\n uint128 internal immutable _maxBatchSize;\n uint128 internal immutable _messageGasLimit;\n\n constructor(uint128 maxBatchSize_, uint128 messageGasLimit) {\n _maxBatchSize = maxBatchSize_;\n _messageGasLimit = messageGasLimit;\n }\n\n /// @inheritdoc IGasService\n function maxBatchSize(uint16) public view returns (uint128) {\n return _maxBatchSize;\n }\n\n /// @inheritdoc IGasService\n function gasLimit(uint16, bytes calldata) public view returns (uint128) {\n return _messageGasLimit;\n }\n}\n" + }, + "src/common/Gateway.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {ArrayLib} from \"src/misc/libraries/ArrayLib.sol\";\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {Recoverable, IRecoverable, ETH_ADDRESS} from \"src/misc/Recoverable.sol\";\nimport {TransientArrayLib} from \"src/misc/libraries/TransientArrayLib.sol\";\nimport {TransientBytesLib} from \"src/misc/libraries/TransientBytesLib.sol\";\nimport {TransientStorageLib} from \"src/misc/libraries/TransientStorageLib.sol\";\n\nimport {IRoot} from \"src/common/interfaces/IRoot.sol\";\nimport {IGasService} from \"src/common/interfaces/IGasService.sol\";\nimport {IAdapter} from \"src/common/interfaces/IAdapter.sol\";\nimport {IMessageProcessor} from \"src/common/interfaces/IMessageProcessor.sol\";\nimport {IMessageSender} from \"src/common/interfaces/IMessageSender.sol\";\nimport {IGateway} from \"src/common/interfaces/IGateway.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {IGatewayHandler} from \"src/common/interfaces/IGatewayHandlers.sol\";\nimport {MessageProofLib} from \"src/common/libraries/MessageProofLib.sol\";\n\n/// @title Gateway\n/// @notice Routing contract that forwards outgoing messages to multiple adapters (1 full message, n-1 proofs)\n/// and validates that multiple adapters have confirmed a message.\n///\n/// Supports batching multiple messages, as well as paying for methods manually or through pool-level subsidies.\n///\n/// Supports processing multiple duplicate messages in parallel by storing counts of messages\n/// and proofs that have been received. Also implements a retry method for failed messages.\ncontract Gateway is Auth, Recoverable, IGateway {\n using BytesLib for bytes;\n using MathLib for uint256;\n using MessageProofLib for *;\n using ArrayLib for uint16[8];\n using TransientStorageLib for bytes32;\n\n uint8 public constant MAX_ADAPTER_COUNT = 8;\n uint8 public constant PRIMARY_ADAPTER_ID = 1;\n PoolId public constant GLOBAL_POT = PoolId.wrap(0);\n uint256 public constant RECOVERY_CHALLENGE_PERIOD = 7 days;\n bytes32 public constant BATCH_LOCATORS_SLOT = bytes32(uint256(keccak256(\"Centrifuge/batch-locators\")) - 1);\n\n uint16 public immutable localCentrifugeId;\n\n // Dependencies\n IRoot public immutable root;\n IGasService public gasService;\n IMessageProcessor public processor;\n\n // Outbound & payments\n bool public transient isBatching;\n uint256 public transient fuel;\n address public transient transactionRefund;\n mapping(PoolId => Funds) public subsidy;\n mapping(uint16 centrifugeId => mapping(bytes32 batchHash => Underpaid)) public underpaid;\n\n // Adapters\n mapping(uint16 centrifugeId => IAdapter[]) public adapters;\n mapping(uint16 centrifugeId => mapping(IAdapter adapter => Adapter)) internal _activeAdapters;\n\n // Inbound & recoveries\n mapping(uint16 centrifugeId => mapping(bytes32 messageHash => uint256)) public failedMessages;\n mapping(uint16 centrifugeId => mapping(bytes32 batchHash => InboundBatch)) public inboundBatch;\n mapping(uint16 centrifugeId => mapping(IAdapter adapter => mapping(bytes32 payloadHash => uint256 timestamp)))\n public recoveries;\n\n constructor(uint16 localCentrifugeId_, IRoot root_, IGasService gasService_, address deployer) Auth(deployer) {\n localCentrifugeId = localCentrifugeId_;\n root = root_;\n gasService = gasService_;\n\n setRefundAddress(GLOBAL_POT, IRecoverable(address(this)));\n }\n\n modifier pauseable() {\n require(!root.paused(), Paused());\n _;\n }\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IGateway\n function file(bytes32 what, uint16 centrifugeId, IAdapter[] calldata addresses) external auth {\n if (what == \"adapters\") {\n uint8 quorum_ = addresses.length.toUint8();\n require(quorum_ != 0, EmptyAdapterSet());\n require(quorum_ <= MAX_ADAPTER_COUNT, ExceedsMax());\n\n // Increment session id to reset pending votes\n uint256 numAdapters = adapters[centrifugeId].length;\n uint64 sessionId =\n numAdapters > 0 ? _activeAdapters[centrifugeId][adapters[centrifugeId][0]].activeSessionId + 1 : 0;\n\n // Disable old adapters\n for (uint8 i; i < numAdapters; i++) {\n delete _activeAdapters[centrifugeId][adapters[centrifugeId][i]];\n }\n\n // Enable new adapters, setting quorum to number of adapters\n for (uint8 j; j < quorum_; j++) {\n require(_activeAdapters[centrifugeId][addresses[j]].id == 0, NoDuplicatesAllowed());\n\n // Ids are assigned sequentially starting at 1\n _activeAdapters[centrifugeId][addresses[j]] = Adapter(j + 1, quorum_, sessionId);\n }\n\n adapters[centrifugeId] = addresses;\n } else {\n revert FileUnrecognizedParam();\n }\n\n emit File(what, centrifugeId, addresses);\n }\n\n /// @inheritdoc IGateway\n function file(bytes32 what, address instance) external auth {\n if (what == \"gasService\") gasService = IGasService(instance);\n else if (what == \"processor\") processor = IMessageProcessor(instance);\n else revert FileUnrecognizedParam();\n\n emit File(what, instance);\n }\n\n receive() external payable {\n _subsidizePool(GLOBAL_POT, msg.sender, msg.value);\n }\n\n //----------------------------------------------------------------------------------------------\n // Incoming\n //----------------------------------------------------------------------------------------------\n\n /// @dev Handle an inbound payload\n function handle(uint16 centrifugeId, bytes calldata payload) external pauseable {\n _handle(centrifugeId, payload, IAdapter(msg.sender), false);\n }\n\n function _handle(uint16 centrifugeId, bytes calldata payload, IAdapter adapter_, bool isRecovery) internal {\n Adapter memory adapter = _activeAdapters[centrifugeId][adapter_];\n require(adapter.id != 0, InvalidAdapter());\n\n IMessageProcessor processor_ = processor;\n if (processor_.isMessageRecovery(payload)) {\n require(!isRecovery, RecoveryPayloadRecovered());\n return processor_.handle(centrifugeId, payload);\n }\n\n bool isMessageProof = payload.toUint8(0) == MessageProofLib.MESSAGE_PROOF_ID;\n\n // Verify adapter and parse message hash\n bytes32 batchHash;\n if (isMessageProof) {\n require(adapter.id != PRIMARY_ADAPTER_ID, NonProofAdapter());\n\n batchHash = payload.deserializeMessageProof();\n bytes32 payloadId = keccak256(abi.encodePacked(centrifugeId, localCentrifugeId, batchHash));\n emit HandleProof(centrifugeId, payloadId, batchHash, adapter_);\n } else {\n require(adapter.id == PRIMARY_ADAPTER_ID, NonBatchAdapter());\n\n batchHash = keccak256(payload);\n bytes32 payloadId = keccak256(abi.encodePacked(centrifugeId, localCentrifugeId, batchHash));\n emit HandleBatch(centrifugeId, payloadId, payload, adapter_);\n }\n\n // Special case for gas efficiency\n if (adapter.quorum == 1 && !isMessageProof) {\n _handleBatch(centrifugeId, payload);\n return;\n }\n\n InboundBatch storage state = inboundBatch[centrifugeId][batchHash];\n\n if (adapter.activeSessionId != state.sessionId) {\n // Clear votes from previous session\n delete state.votes;\n state.sessionId = adapter.activeSessionId;\n }\n\n // Increase vote\n state.votes[adapter.id - 1]++;\n\n if (state.votes.countNonZeroValues() >= adapter.quorum) {\n // Reduce votes by quorum\n state.votes.decreaseFirstNValues(adapter.quorum);\n\n if (isMessageProof) {\n _handleBatch(centrifugeId, state.pendingBatch);\n } else {\n _handleBatch(centrifugeId, payload);\n }\n\n // Only if there are no more pending messages, remove the pending message\n if (state.votes.isEmpty()) {\n delete state.pendingBatch;\n }\n } else if (!isMessageProof) {\n state.pendingBatch = payload;\n }\n }\n\n function _handleBatch(uint16 centrifugeId, bytes memory batch_) internal {\n IMessageProcessor processor_ = processor;\n bytes memory remaining = batch_;\n\n while (remaining.length > 0) {\n uint256 length = processor_.messageLength(remaining);\n bytes memory message = remaining.slice(0, length);\n remaining = remaining.slice(length, remaining.length - length);\n\n try processor_.handle(centrifugeId, message) {\n emit ExecuteMessage(centrifugeId, message);\n } catch (bytes memory err) {\n bytes32 messageHash = keccak256(message);\n failedMessages[centrifugeId][messageHash]++;\n emit FailMessage(centrifugeId, message, err);\n }\n }\n }\n\n /// @inheritdoc IGateway\n function retry(uint16 centrifugeId, bytes memory message) external pauseable {\n bytes32 messageHash = keccak256(message);\n require(failedMessages[centrifugeId][messageHash] > 0, NotFailedMessage());\n\n processor.handle(centrifugeId, message);\n failedMessages[centrifugeId][messageHash]--;\n\n emit ExecuteMessage(centrifugeId, message);\n }\n\n /// @inheritdoc IGatewayHandler\n function initiateRecovery(uint16 centrifugeId, IAdapter adapter, bytes32 payloadHash) external auth {\n require(_activeAdapters[centrifugeId][adapter].id != 0, InvalidAdapter());\n recoveries[centrifugeId][adapter][payloadHash] = block.timestamp + RECOVERY_CHALLENGE_PERIOD;\n emit InitiateRecovery(centrifugeId, payloadHash, adapter);\n }\n\n /// @inheritdoc IGatewayHandler\n function disputeRecovery(uint16 centrifugeId, IAdapter adapter, bytes32 payloadHash) external auth {\n delete recoveries[centrifugeId][adapter][payloadHash];\n emit DisputeRecovery(centrifugeId, payloadHash, adapter);\n }\n\n /// @inheritdoc IGateway\n function executeRecovery(uint16 centrifugeId, IAdapter adapter, bytes calldata payload) external {\n bytes32 payloadHash = keccak256(payload);\n uint256 recovery = recoveries[centrifugeId][adapter][payloadHash];\n\n require(recovery != 0, RecoveryNotInitiated());\n require(recovery <= block.timestamp, RecoveryChallengePeriodNotEnded());\n\n delete recoveries[centrifugeId][adapter][payloadHash];\n _handle(centrifugeId, payload, adapter, true);\n emit ExecuteRecovery(centrifugeId, payload, adapter);\n }\n\n //----------------------------------------------------------------------------------------------\n // Outgoing\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IMessageSender\n function send(uint16 centrifugeId, bytes calldata message) external pauseable auth {\n require(message.length > 0, EmptyMessage());\n\n PoolId poolId = processor.messagePoolId(message);\n\n emit PrepareMessage(centrifugeId, poolId, message);\n\n if (isBatching) {\n bytes32 batchSlot = _outboundBatchSlot(centrifugeId, poolId);\n bytes memory previousMessage = TransientBytesLib.get(batchSlot);\n\n bytes32 gasLimitSlot = _gasLimitSlot(centrifugeId, poolId);\n uint128 newGasLimit = gasLimitSlot.tloadUint128() + gasService.gasLimit(centrifugeId, message);\n require(newGasLimit <= gasService.maxBatchSize(centrifugeId), ExceedsMaxBatchSize());\n gasLimitSlot.tstore(uint256(newGasLimit));\n\n if (previousMessage.length == 0) {\n TransientArrayLib.push(BATCH_LOCATORS_SLOT, _encodeLocator(centrifugeId, poolId));\n }\n\n TransientBytesLib.append(batchSlot, message);\n } else {\n _send(centrifugeId, poolId, message, gasService.gasLimit(centrifugeId, message));\n _refundTransaction();\n }\n }\n\n function _send(uint16 centrifugeId, PoolId poolId, bytes memory batch, uint128 batchGasLimit)\n internal\n returns (bool succeeded)\n {\n IAdapter[] memory adapters_ = adapters[centrifugeId];\n require(adapters[centrifugeId].length != 0, EmptyAdapterSet());\n\n SendData memory data = SendData({\n batchHash: keccak256(batch),\n payloadId: bytes32(\"\"),\n gasCost: new uint256[](MAX_ADAPTER_COUNT)\n });\n data.payloadId = keccak256(abi.encodePacked(localCentrifugeId, centrifugeId, data.batchHash));\n\n {\n // Estimate gas usage\n uint256 total;\n for (uint256 i; i < adapters_.length; i++) {\n data.gasCost[i] = adapters_[i].estimate(\n centrifugeId,\n i == PRIMARY_ADAPTER_ID - 1 ? batch : data.batchHash.serializeMessageProof(),\n batchGasLimit\n );\n\n total += data.gasCost[i];\n }\n\n // Ensure sufficient funds are available\n if (transactionRefund != address(0)) {\n require(total <= fuel, NotEnoughTransactionGas());\n fuel -= total;\n } else {\n if (total > subsidy[poolId].value) {\n _requestPoolFunding(poolId);\n }\n\n if (total <= subsidy[poolId].value) {\n subsidy[poolId].value -= uint96(total);\n } else {\n underpaid[centrifugeId][data.batchHash].counter++;\n underpaid[centrifugeId][data.batchHash].gasLimit = batchGasLimit;\n emit UnderpaidBatch(centrifugeId, batch);\n return false;\n }\n }\n }\n\n // Send batch and proofs\n for (uint256 j; j < adapters_.length; j++) {\n bytes32 adapterData = adapters_[j].send{value: data.gasCost[j]}(\n centrifugeId,\n j == PRIMARY_ADAPTER_ID - 1 ? batch : data.batchHash.serializeMessageProof(),\n batchGasLimit,\n transactionRefund != address(0) ? transactionRefund : address(subsidy[poolId].refund)\n );\n\n if (j == PRIMARY_ADAPTER_ID - 1) {\n emit SendBatch(\n centrifugeId,\n data.payloadId,\n batch,\n adapters_[j],\n adapterData,\n transactionRefund != address(0) ? transactionRefund : address(subsidy[poolId].refund)\n );\n } else {\n emit SendProof(\n centrifugeId,\n data.payloadId,\n data.batchHash,\n adapters_[j],\n adapterData\n );\n }\n }\n\n return true;\n }\n\n /// @inheritdoc IGateway\n function repay(uint16 centrifugeId, bytes memory batch) external payable pauseable {\n bytes32 batchHash = keccak256(batch);\n Underpaid storage underpaid_ = underpaid[centrifugeId][batchHash];\n require(underpaid_.counter > 0, NotUnderpaidBatch());\n\n PoolId poolId = processor.messagePoolId(batch);\n if (msg.value > 0) subsidizePool(poolId);\n\n require(_send(centrifugeId, poolId, batch, underpaid_.gasLimit), InsufficientFundsForRepayment());\n underpaid[centrifugeId][batchHash].counter--;\n\n emit RepayBatch(centrifugeId, batch);\n }\n\n function _refundTransaction() internal {\n if (transactionRefund == address(0)) return;\n\n // Reset before external call\n uint256 fuel_ = fuel;\n address transactionRefund_ = transactionRefund;\n fuel = 0;\n transactionRefund = address(0);\n\n if (fuel_ > 0) {\n (bool success,) = payable(transactionRefund_).call{value: fuel_}(new bytes(0));\n\n if (!success) {\n // If refund fails, move remaining fuel to global pot\n _subsidizePool(GLOBAL_POT, transactionRefund_, fuel_);\n }\n }\n }\n\n function _requestPoolFunding(PoolId poolId) internal {\n IRecoverable refund = subsidy[poolId].refund;\n if (!poolId.isNull() && address(refund) != address(0)) {\n uint256 refundBalance = address(refund).balance;\n if (refundBalance == 0) return;\n\n // Send to the gateway GLOBAL_POT\n refund.recoverTokens(ETH_ADDRESS, address(this), refundBalance);\n\n // Extract from the GLOBAL_POT\n subsidy[GLOBAL_POT].value -= uint96(refundBalance);\n _subsidizePool(poolId, address(refund), refundBalance);\n }\n }\n\n /// @inheritdoc IGateway\n function setRefundAddress(PoolId poolId, IRecoverable refund) public auth {\n subsidy[poolId].refund = refund;\n emit SetRefundAddress(poolId, refund);\n }\n\n /// @inheritdoc IGateway\n function subsidizePool(PoolId poolId) public payable {\n require(address(subsidy[poolId].refund) != address(0), RefundAddressNotSet());\n _subsidizePool(poolId, msg.sender, msg.value);\n }\n\n function _subsidizePool(PoolId poolId, address who, uint256 value) internal {\n subsidy[poolId].value += uint96(value);\n emit SubsidizePool(poolId, who, value);\n }\n\n /// @inheritdoc IGateway\n function payTransaction(address payer) external payable auth {\n transactionRefund = payer;\n fuel += msg.value;\n }\n\n /// @inheritdoc IGateway\n function startBatching() external auth {\n isBatching = true;\n }\n\n /// @inheritdoc IGateway\n function endBatching() external auth {\n require(isBatching, NoBatched());\n\n bytes32[] memory locators = TransientArrayLib.getBytes32(BATCH_LOCATORS_SLOT);\n for (uint256 i; i < locators.length; i++) {\n (uint16 centrifugeId, PoolId poolId) = _parseLocator(locators[i]);\n bytes32 outboundBatchSlot = _outboundBatchSlot(centrifugeId, poolId);\n uint128 gasLimit = _gasLimitSlot(centrifugeId, poolId).tloadUint128();\n\n _send(centrifugeId, poolId, TransientBytesLib.get(outboundBatchSlot), gasLimit);\n\n TransientBytesLib.clear(outboundBatchSlot);\n _gasLimitSlot(centrifugeId, poolId).tstore(uint256(0));\n }\n\n TransientArrayLib.clear(BATCH_LOCATORS_SLOT);\n isBatching = false;\n\n _refundTransaction();\n }\n\n function _encodeLocator(uint16 centrifugeId, PoolId poolId) internal pure returns (bytes32) {\n return bytes32(abi.encodePacked(bytes2(centrifugeId), bytes8(poolId.raw())));\n }\n\n function _parseLocator(bytes32 locator) internal pure returns (uint16 centrifugeId, PoolId poolId) {\n centrifugeId = uint16(bytes2(locator));\n poolId = PoolId.wrap(uint64(bytes8(locator << 16)));\n }\n\n function _gasLimitSlot(uint16 centrifugeId, PoolId poolId) internal pure returns (bytes32) {\n return keccak256(abi.encode(\"batchGasLimit\", centrifugeId, poolId));\n }\n\n function _outboundBatchSlot(uint16 centrifugeId, PoolId poolId) internal pure returns (bytes32) {\n return keccak256(abi.encode(\"outboundBatch\", centrifugeId, poolId));\n }\n\n //----------------------------------------------------------------------------------------------\n // View methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IGateway\n function estimate(uint16 centrifugeId, bytes calldata payload) external view returns (uint256 total) {\n bytes memory proof = keccak256(payload).serializeMessageProof();\n\n uint256 gasLimit = 0;\n for (uint256 pos; pos < payload.length;) {\n bytes calldata inner = payload[pos:payload.length];\n gasLimit += gasService.gasLimit(centrifugeId, inner);\n pos += processor.messageLength(inner);\n }\n\n uint256 adaptersCount = adapters[centrifugeId].length;\n for (uint256 i; i < adaptersCount; i++) {\n bytes memory message = i == PRIMARY_ADAPTER_ID - 1 ? payload : proof;\n total += IAdapter(adapters[centrifugeId][i]).estimate(centrifugeId, message, gasLimit);\n }\n }\n\n /// @inheritdoc IGateway\n function quorum(uint16 centrifugeId) external view returns (uint8) {\n Adapter memory adapter = _activeAdapters[centrifugeId][adapters[centrifugeId][0]];\n return adapter.quorum;\n }\n\n /// @inheritdoc IGateway\n function activeSessionId(uint16 centrifugeId) external view returns (uint64) {\n Adapter memory adapter = _activeAdapters[centrifugeId][adapters[centrifugeId][0]];\n return adapter.activeSessionId;\n }\n\n /// @inheritdoc IGateway\n function votes(uint16 centrifugeId, bytes32 batchHash) external view returns (uint16[MAX_ADAPTER_COUNT] memory) {\n return inboundBatch[centrifugeId][batchHash].votes;\n }\n}\n\n" + }, + "src/common/Guardian.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {IRoot} from \"src/common/interfaces/IRoot.sol\";\nimport {IAdapter} from \"src/common/interfaces/IAdapter.sol\";\nimport {IGuardian, ISafe} from \"src/common/interfaces/IGuardian.sol\";\nimport {IRootMessageSender} from \"src/common/interfaces/IGatewaySenders.sol\";\nimport {IHubGuardianActions} from \"src/common/interfaces/IGuardianActions.sol\";\n\ncontract Guardian is IGuardian {\n using CastLib for address;\n\n IRoot public immutable root;\n\n IHubGuardianActions public hub;\n ISafe public safe;\n IRootMessageSender public sender;\n\n constructor(ISafe safe_, IRoot root_, IRootMessageSender messageDispatcher_) {\n root = root_;\n safe = safe_;\n sender = messageDispatcher_;\n }\n\n modifier onlySafe() {\n require(msg.sender == address(safe), NotTheAuthorizedSafe());\n _;\n }\n\n modifier onlySafeOrOwner() {\n require(msg.sender == address(safe) || _isSafeOwner(msg.sender), NotTheAuthorizedSafeOrItsOwner());\n _;\n }\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IGuardian\n function file(bytes32 what, address data) external onlySafe {\n if (what == \"safe\") safe = ISafe(data);\n else if (what == \"sender\") sender = IRootMessageSender(data);\n else if (what == \"hub\") hub = IHubGuardianActions(data);\n else revert FileUnrecognizedParam();\n\n emit File(what, data);\n }\n\n //----------------------------------------------------------------------------------------------\n // Admin actions\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IGuardian\n function createPool(PoolId poolId, address admin, AssetId currency) external onlySafe {\n return hub.createPool(poolId, admin, currency);\n }\n\n /// @inheritdoc IGuardian\n function pause() external onlySafeOrOwner {\n root.pause();\n }\n\n /// @inheritdoc IGuardian\n function unpause() external onlySafe {\n root.unpause();\n }\n\n /// @inheritdoc IGuardian\n function scheduleRely(address target) external onlySafe {\n root.scheduleRely(target);\n }\n\n /// @inheritdoc IGuardian\n function cancelRely(address target) external onlySafe {\n root.cancelRely(target);\n }\n\n /// @inheritdoc IGuardian\n function scheduleUpgrade(uint16 centrifugeId, address target) external onlySafe {\n sender.sendScheduleUpgrade(centrifugeId, target.toBytes32());\n }\n\n /// @inheritdoc IGuardian\n function cancelUpgrade(uint16 centrifugeId, address target) external onlySafe {\n sender.sendCancelUpgrade(centrifugeId, target.toBytes32());\n }\n\n /// @inheritdoc IGuardian\n function recoverTokens(\n uint16 centrifugeId,\n address target,\n address token,\n uint256 tokenId,\n address to,\n uint256 amount\n ) external onlySafe {\n sender.sendRecoverTokens(centrifugeId, target.toBytes32(), token.toBytes32(), tokenId, to.toBytes32(), amount);\n }\n\n /// @inheritdoc IGuardian\n function initiateRecovery(uint16 centrifugeId, uint16 adapterCentrifugeId, IAdapter adapter, bytes32 hash)\n external\n onlySafe\n {\n sender.sendInitiateRecovery(centrifugeId, adapterCentrifugeId, address(adapter).toBytes32(), hash);\n }\n\n /// @inheritdoc IGuardian\n function disputeRecovery(uint16 centrifugeId, uint16 adapterCentrifugeId, IAdapter adapter, bytes32 hash)\n external\n onlySafe\n {\n sender.sendDisputeRecovery(centrifugeId, adapterCentrifugeId, address(adapter).toBytes32(), hash);\n }\n\n //----------------------------------------------------------------------------------------------\n // Helpers\n //----------------------------------------------------------------------------------------------\n\n function _isSafeOwner(address addr) internal view returns (bool) {\n try safe.isOwner(addr) returns (bool isOwner) {\n return isOwner;\n } catch {\n return false;\n }\n }\n}\n" + }, + "src/common/MessageDispatcher.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {D18, d18} from \"src/misc/types/D18.sol\";\nimport {IRecoverable} from \"src/misc/interfaces/IRecoverable.sol\";\n\nimport {MessageLib} from \"src/common/libraries/MessageLib.sol\";\nimport {IAdapter} from \"src/common/interfaces/IAdapter.sol\";\nimport {IGateway} from \"src/common/interfaces/IGateway.sol\";\nimport {IRoot} from \"src/common/interfaces/IRoot.sol\";\nimport {\n IRequestManagerGatewayHandler,\n IPoolManagerGatewayHandler,\n IBalanceSheetGatewayHandler,\n IHubGatewayHandler\n} from \"src/common/interfaces/IGatewayHandlers.sol\";\nimport {IVaultMessageSender, IPoolMessageSender, IRootMessageSender} from \"src/common/interfaces/IGatewaySenders.sol\";\n\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {IMessageDispatcher} from \"src/common/interfaces/IMessageDispatcher.sol\";\nimport {ITokenRecoverer} from \"src/common/interfaces/ITokenRecoverer.sol\";\n\ncontract MessageDispatcher is Auth, IMessageDispatcher {\n using CastLib for *;\n using MessageLib for *;\n using BytesLib for bytes;\n using MathLib for uint256;\n\n IRoot public immutable root;\n IGateway public immutable gateway;\n ITokenRecoverer public immutable tokenRecoverer;\n\n uint16 public immutable localCentrifugeId;\n\n IHubGatewayHandler public hub;\n IPoolManagerGatewayHandler public poolManager;\n IRequestManagerGatewayHandler public investmentManager;\n IBalanceSheetGatewayHandler public balanceSheet;\n\n constructor(\n uint16 localCentrifugeId_,\n IRoot root_,\n IGateway gateway_,\n ITokenRecoverer tokenRecoverer_,\n address deployer\n ) Auth(deployer) {\n localCentrifugeId = localCentrifugeId_;\n root = root_;\n gateway = gateway_;\n tokenRecoverer = tokenRecoverer_;\n }\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IMessageDispatcher\n function file(bytes32 what, address data) external auth {\n if (what == \"hub\") hub = IHubGatewayHandler(data);\n else if (what == \"poolManager\") poolManager = IPoolManagerGatewayHandler(data);\n else if (what == \"investmentManager\") investmentManager = IRequestManagerGatewayHandler(data);\n else if (what == \"balanceSheet\") balanceSheet = IBalanceSheetGatewayHandler(data);\n else revert FileUnrecognizedParam();\n\n emit File(what, data);\n }\n\n //----------------------------------------------------------------------------------------------\n // Helpers\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IMessageDispatcher\n function estimate(uint16 centrifugeId, bytes calldata payload) external view returns (uint256 amount) {\n if (centrifugeId == localCentrifugeId) return 0;\n return gateway.estimate(centrifugeId, payload);\n }\n\n //----------------------------------------------------------------------------------------------\n // Outgoing\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IPoolMessageSender\n function sendNotifyPool(uint16 centrifugeId, PoolId poolId) external auth {\n if (centrifugeId == localCentrifugeId) {\n poolManager.addPool(poolId);\n } else {\n gateway.send(centrifugeId, MessageLib.NotifyPool({poolId: poolId.raw()}).serialize());\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendNotifyShareClass(\n uint16 centrifugeId,\n PoolId poolId,\n ShareClassId scId,\n string memory name,\n string memory symbol,\n uint8 decimals,\n bytes32 salt,\n bytes32 hook\n ) external auth {\n if (centrifugeId == localCentrifugeId) {\n poolManager.addShareClass(poolId, scId, name, symbol, decimals, salt, hook.toAddress());\n } else {\n gateway.send(\n centrifugeId,\n MessageLib.NotifyShareClass({\n poolId: poolId.raw(),\n scId: scId.raw(),\n name: name,\n symbol: symbol.toBytes32(),\n decimals: decimals,\n salt: salt,\n hook: hook\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendNotifyShareMetadata(\n uint16 centrifugeId,\n PoolId poolId,\n ShareClassId scId,\n string memory name,\n string memory symbol\n ) external auth {\n if (centrifugeId == localCentrifugeId) {\n poolManager.updateShareMetadata(poolId, scId, name, symbol);\n } else {\n gateway.send(\n centrifugeId,\n MessageLib.NotifyShareMetadata({\n poolId: poolId.raw(),\n scId: scId.raw(),\n name: name,\n symbol: symbol.toBytes32()\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendUpdateShareHook(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bytes32 hook) external auth {\n if (centrifugeId == localCentrifugeId) {\n poolManager.updateShareHook(poolId, scId, hook.toAddress());\n } else {\n gateway.send(\n centrifugeId,\n MessageLib.UpdateShareHook({poolId: poolId.raw(), scId: scId.raw(), hook: hook}).serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendNotifyPricePoolPerShare(uint16 chainId, PoolId poolId, ShareClassId scId, D18 sharePrice)\n external\n auth\n {\n uint64 timestamp = block.timestamp.toUint64();\n if (chainId == localCentrifugeId) {\n poolManager.updatePricePoolPerShare(poolId, scId, sharePrice.raw(), timestamp);\n } else {\n gateway.send(\n chainId,\n MessageLib.NotifyPricePoolPerShare({\n poolId: poolId.raw(),\n scId: scId.raw(),\n price: sharePrice.raw(),\n timestamp: timestamp\n }).serialize()\n );\n }\n }\n\n function sendNotifyPricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId, D18 price) external auth {\n uint64 timestamp = block.timestamp.toUint64();\n if (assetId.centrifugeId() == localCentrifugeId) {\n poolManager.updatePricePoolPerAsset(poolId, scId, assetId, price.raw(), timestamp);\n } else {\n gateway.send(\n assetId.centrifugeId(),\n MessageLib.NotifyPricePoolPerAsset({\n poolId: poolId.raw(),\n scId: scId.raw(),\n assetId: assetId.raw(),\n price: price.raw(),\n timestamp: timestamp\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendFulfilledDepositRequest(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n bytes32 investor,\n uint128 assetAmount,\n uint128 shareAmount\n ) external auth {\n if (assetId.centrifugeId() == localCentrifugeId) {\n investmentManager.fulfillDepositRequest(\n poolId, scId, investor.toAddress(), assetId, assetAmount, shareAmount\n );\n } else {\n gateway.send(\n assetId.centrifugeId(),\n MessageLib.FulfilledDepositRequest({\n poolId: poolId.raw(),\n scId: scId.raw(),\n investor: investor,\n assetId: assetId.raw(),\n assetAmount: assetAmount,\n shareAmount: shareAmount\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendFulfilledRedeemRequest(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n bytes32 investor,\n uint128 assetAmount,\n uint128 shareAmount\n ) external auth {\n if (assetId.centrifugeId() == localCentrifugeId) {\n investmentManager.fulfillRedeemRequest(\n poolId, scId, investor.toAddress(), assetId, assetAmount, shareAmount\n );\n } else {\n gateway.send(\n assetId.centrifugeId(),\n MessageLib.FulfilledRedeemRequest({\n poolId: poolId.raw(),\n scId: scId.raw(),\n investor: investor,\n assetId: assetId.raw(),\n assetAmount: assetAmount,\n shareAmount: shareAmount\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendFulfilledCancelDepositRequest(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n bytes32 investor,\n uint128 cancelledAmount\n ) external auth {\n if (assetId.centrifugeId() == localCentrifugeId) {\n investmentManager.fulfillCancelDepositRequest(\n poolId, scId, investor.toAddress(), assetId, cancelledAmount, cancelledAmount\n );\n } else {\n gateway.send(\n assetId.centrifugeId(),\n MessageLib.FulfilledCancelDepositRequest({\n poolId: poolId.raw(),\n scId: scId.raw(),\n investor: investor,\n assetId: assetId.raw(),\n cancelledAmount: cancelledAmount\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendFulfilledCancelRedeemRequest(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n bytes32 investor,\n uint128 cancelledShares\n ) external auth {\n if (assetId.centrifugeId() == localCentrifugeId) {\n investmentManager.fulfillCancelRedeemRequest(poolId, scId, investor.toAddress(), assetId, cancelledShares);\n } else {\n gateway.send(\n assetId.centrifugeId(),\n MessageLib.FulfilledCancelRedeemRequest({\n poolId: poolId.raw(),\n scId: scId.raw(),\n investor: investor,\n assetId: assetId.raw(),\n cancelledShares: cancelledShares\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendUpdateRestriction(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bytes calldata payload)\n external\n auth\n {\n if (centrifugeId == localCentrifugeId) {\n poolManager.updateRestriction(poolId, scId, payload);\n } else {\n gateway.send(\n centrifugeId,\n MessageLib.UpdateRestriction({poolId: poolId.raw(), scId: scId.raw(), payload: payload}).serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendUpdateContract(\n uint16 centrifugeId,\n PoolId poolId,\n ShareClassId scId,\n bytes32 target,\n bytes calldata payload\n ) external auth {\n if (centrifugeId == localCentrifugeId) {\n poolManager.updateContract(poolId, scId, target.toAddress(), payload);\n } else {\n gateway.send(\n centrifugeId,\n MessageLib.UpdateContract({poolId: poolId.raw(), scId: scId.raw(), target: target, payload: payload})\n .serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendApprovedDeposits(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n uint128 assetAmount,\n D18 pricePoolPerAsset\n ) external auth {\n if (assetId.centrifugeId() == localCentrifugeId) {\n investmentManager.approvedDeposits(poolId, scId, assetId, assetAmount, pricePoolPerAsset);\n } else {\n gateway.send(\n assetId.centrifugeId(),\n MessageLib.ApprovedDeposits({\n poolId: poolId.raw(),\n scId: scId.raw(),\n assetId: assetId.raw(),\n assetAmount: assetAmount,\n pricePoolPerAsset: pricePoolPerAsset.raw()\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendIssuedShares(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n uint128 shareAmount,\n D18 pricePoolPerShare\n ) external auth {\n if (assetId.centrifugeId() == localCentrifugeId) {\n investmentManager.issuedShares(poolId, scId, shareAmount, pricePoolPerShare);\n } else {\n gateway.send(\n assetId.centrifugeId(),\n MessageLib.IssuedShares({\n poolId: poolId.raw(),\n scId: scId.raw(),\n shareAmount: shareAmount,\n pricePoolPerShare: pricePoolPerShare.raw()\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendRevokedShares(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n uint128 assetAmount,\n uint128 shareAmount,\n D18 pricePoolPerShare\n ) external auth {\n if (assetId.centrifugeId() == localCentrifugeId) {\n investmentManager.revokedShares(poolId, scId, assetId, assetAmount, shareAmount, pricePoolPerShare);\n } else {\n gateway.send(\n assetId.centrifugeId(),\n MessageLib.RevokedShares({\n poolId: poolId.raw(),\n scId: scId.raw(),\n assetId: assetId.raw(),\n assetAmount: assetAmount,\n shareAmount: shareAmount,\n pricePoolPerShare: pricePoolPerShare.raw()\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendTriggerIssueShares(uint16 centrifugeId, PoolId poolId, ShareClassId scId, address who, uint128 shares)\n external\n auth\n {\n if (centrifugeId == localCentrifugeId) {\n balanceSheet.triggerIssueShares(poolId, scId, who, shares);\n } else {\n gateway.send(\n centrifugeId,\n MessageLib.TriggerIssueShares({\n poolId: poolId.raw(),\n scId: scId.raw(),\n who: who.toBytes32(),\n shares: shares\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendTriggerSubmitQueuedShares(uint16 centrifugeId, PoolId poolId, ShareClassId scId) external auth {\n if (centrifugeId == localCentrifugeId) {\n balanceSheet.submitQueuedShares(poolId, scId);\n } else {\n gateway.send(\n centrifugeId, MessageLib.TriggerSubmitQueuedShares({poolId: poolId.raw(), scId: scId.raw()}).serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendTriggerSubmitQueuedAssets(PoolId poolId, ShareClassId scId, AssetId assetId) external auth {\n if (assetId.centrifugeId() == localCentrifugeId) {\n balanceSheet.submitQueuedAssets(poolId, scId, assetId);\n } else {\n gateway.send(\n assetId.centrifugeId(),\n MessageLib.TriggerSubmitQueuedAssets({poolId: poolId.raw(), scId: scId.raw(), assetId: assetId.raw()})\n .serialize()\n );\n }\n }\n\n /// @inheritdoc IPoolMessageSender\n function sendSetQueue(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bool enabled) external auth {\n if (centrifugeId == localCentrifugeId) {\n balanceSheet.setQueue(poolId, scId, enabled);\n } else {\n gateway.send(\n centrifugeId,\n MessageLib.SetQueue({poolId: poolId.raw(), scId: scId.raw(), enabled: enabled}).serialize()\n );\n }\n }\n\n /// @inheritdoc IRootMessageSender\n function sendScheduleUpgrade(uint16 centrifugeId, bytes32 target) external auth {\n if (centrifugeId == localCentrifugeId) {\n root.scheduleRely(target.toAddress());\n } else {\n gateway.send(centrifugeId, MessageLib.ScheduleUpgrade({target: target}).serialize());\n }\n }\n\n /// @inheritdoc IRootMessageSender\n function sendCancelUpgrade(uint16 centrifugeId, bytes32 target) external auth {\n if (centrifugeId == localCentrifugeId) {\n root.cancelRely(target.toAddress());\n } else {\n gateway.send(centrifugeId, MessageLib.CancelUpgrade({target: target}).serialize());\n }\n }\n\n /// @inheritdoc IRootMessageSender\n function sendRecoverTokens(\n uint16 centrifugeId,\n bytes32 target,\n bytes32 token,\n uint256 tokenId,\n bytes32 to,\n uint256 amount\n ) external auth {\n if (centrifugeId == localCentrifugeId) {\n tokenRecoverer.recoverTokens(\n IRecoverable(target.toAddress()), token.toAddress(), tokenId, to.toAddress(), amount\n );\n } else {\n gateway.send(\n centrifugeId,\n MessageLib.RecoverTokens({target: target, token: token, tokenId: tokenId, to: to, amount: amount})\n .serialize()\n );\n }\n }\n\n /// @inheritdoc IRootMessageSender\n function sendInitiateRecovery(uint16 centrifugeId, uint16 adapterCentrifugeId, bytes32 adapter, bytes32 hash)\n external\n auth\n {\n if (centrifugeId == localCentrifugeId) {\n gateway.initiateRecovery(adapterCentrifugeId, IAdapter(adapter.toAddress()), hash);\n } else {\n gateway.send(\n centrifugeId,\n MessageLib.InitiateRecovery({hash: hash, adapter: adapter, centrifugeId: adapterCentrifugeId}).serialize(\n )\n );\n }\n }\n\n /// @inheritdoc IRootMessageSender\n function sendDisputeRecovery(uint16 centrifugeId, uint16 adapterCentrifugeId, bytes32 adapter, bytes32 hash)\n external\n auth\n {\n if (centrifugeId == localCentrifugeId) {\n gateway.disputeRecovery(adapterCentrifugeId, IAdapter(adapter.toAddress()), hash);\n } else {\n gateway.send(\n centrifugeId,\n MessageLib.DisputeRecovery({hash: hash, adapter: adapter, centrifugeId: adapterCentrifugeId}).serialize(\n )\n );\n }\n }\n\n /// @inheritdoc IVaultMessageSender\n function sendTransferShares(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bytes32 receiver, uint128 amount)\n external\n auth\n {\n if (centrifugeId == localCentrifugeId) {\n poolManager.handleTransferShares(poolId, scId, receiver.toAddress(), amount);\n } else {\n gateway.send(\n centrifugeId,\n MessageLib.TransferShares({poolId: poolId.raw(), scId: scId.raw(), receiver: receiver, amount: amount})\n .serialize()\n );\n }\n }\n\n /// @inheritdoc IVaultMessageSender\n function sendDepositRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId assetId, uint128 amount)\n external\n auth\n {\n if (poolId.centrifugeId() == localCentrifugeId) {\n hub.depositRequest(poolId, scId, investor, assetId, amount);\n } else {\n gateway.send(\n poolId.centrifugeId(),\n MessageLib.DepositRequest({\n poolId: poolId.raw(),\n scId: scId.raw(),\n investor: investor,\n assetId: assetId.raw(),\n amount: amount\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IVaultMessageSender\n function sendRedeemRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId assetId, uint128 amount)\n external\n auth\n {\n if (poolId.centrifugeId() == localCentrifugeId) {\n hub.redeemRequest(poolId, scId, investor, assetId, amount);\n } else {\n gateway.send(\n poolId.centrifugeId(),\n MessageLib.RedeemRequest({\n poolId: poolId.raw(),\n scId: scId.raw(),\n investor: investor,\n assetId: assetId.raw(),\n amount: amount\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IVaultMessageSender\n function sendCancelDepositRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId assetId)\n external\n auth\n {\n if (poolId.centrifugeId() == localCentrifugeId) {\n hub.cancelDepositRequest(poolId, scId, investor, assetId);\n } else {\n gateway.send(\n poolId.centrifugeId(),\n MessageLib.CancelDepositRequest({\n poolId: poolId.raw(),\n scId: scId.raw(),\n investor: investor,\n assetId: assetId.raw()\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IVaultMessageSender\n function sendCancelRedeemRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId assetId)\n external\n auth\n {\n if (poolId.centrifugeId() == localCentrifugeId) {\n hub.cancelRedeemRequest(poolId, scId, investor, assetId);\n } else {\n gateway.send(\n poolId.centrifugeId(),\n MessageLib.CancelRedeemRequest({\n poolId: poolId.raw(),\n scId: scId.raw(),\n investor: investor,\n assetId: assetId.raw()\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IVaultMessageSender\n function sendUpdateHoldingAmount(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n address provider,\n uint128 amount,\n D18 pricePoolPerAsset,\n bool isIncrease\n ) external auth {\n if (poolId.centrifugeId() == localCentrifugeId) {\n hub.updateHoldingAmount(poolId, scId, assetId, amount, pricePoolPerAsset, isIncrease);\n } else {\n gateway.send(\n poolId.centrifugeId(),\n MessageLib.UpdateHoldingAmount({\n poolId: poolId.raw(),\n scId: scId.raw(),\n assetId: assetId.raw(),\n who: provider.toBytes32(),\n amount: amount,\n pricePerUnit: pricePoolPerAsset.raw(),\n timestamp: uint64(block.timestamp),\n isIncrease: isIncrease\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IVaultMessageSender\n function sendUpdateShares(PoolId poolId, ShareClassId scId, uint128 shares, bool isIssuance) external auth {\n if (poolId.centrifugeId() == localCentrifugeId) {\n if (isIssuance) {\n hub.increaseShareIssuance(poolId, scId, shares);\n } else {\n hub.decreaseShareIssuance(poolId, scId, shares);\n }\n } else {\n gateway.send(\n poolId.centrifugeId(),\n MessageLib.UpdateShares({\n poolId: poolId.raw(),\n scId: scId.raw(),\n shares: shares,\n timestamp: uint64(block.timestamp),\n isIssuance: isIssuance\n }).serialize()\n );\n }\n }\n\n /// @inheritdoc IVaultMessageSender\n function sendRegisterAsset(uint16 centrifugeId, AssetId assetId, uint8 decimals) external auth {\n if (centrifugeId == localCentrifugeId) {\n hub.registerAsset(assetId, decimals);\n } else {\n gateway.send(\n centrifugeId, MessageLib.RegisterAsset({assetId: assetId.raw(), decimals: decimals}).serialize()\n );\n }\n }\n}\n" + }, + "src/common/MessageProcessor.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {D18, d18} from \"src/misc/types/D18.sol\";\nimport {IRecoverable} from \"src/misc/interfaces/IRecoverable.sol\";\n\nimport {MessageType, MessageLib} from \"src/common/libraries/MessageLib.sol\";\nimport {IAdapter} from \"src/common/interfaces/IAdapter.sol\";\nimport {IMessageHandler} from \"src/common/interfaces/IMessageHandler.sol\";\nimport {IMessageProcessor} from \"src/common/interfaces/IMessageProcessor.sol\";\nimport {IMessageProperties} from \"src/common/interfaces/IMessageProperties.sol\";\nimport {IRoot} from \"src/common/interfaces/IRoot.sol\";\nimport {\n IGatewayHandler,\n IPoolManagerGatewayHandler,\n IBalanceSheetGatewayHandler,\n IHubGatewayHandler,\n IRequestManagerGatewayHandler\n} from \"src/common/interfaces/IGatewayHandlers.sol\";\n\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ITokenRecoverer} from \"src/common/interfaces/ITokenRecoverer.sol\";\n\ncontract MessageProcessor is Auth, IMessageProcessor {\n using CastLib for *;\n using MessageLib for *;\n using BytesLib for bytes;\n\n IRoot public immutable root;\n ITokenRecoverer public immutable tokenRecoverer;\n\n IGatewayHandler public gateway;\n IHubGatewayHandler public hub;\n IPoolManagerGatewayHandler public poolManager;\n IRequestManagerGatewayHandler public investmentManager;\n IBalanceSheetGatewayHandler public balanceSheet;\n\n constructor(IRoot root_, ITokenRecoverer tokenRecoverer_, address deployer) Auth(deployer) {\n root = root_;\n tokenRecoverer = tokenRecoverer_;\n }\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IMessageProcessor\n function file(bytes32 what, address data) external auth {\n if (what == \"gateway\") gateway = IGatewayHandler(data);\n else if (what == \"hub\") hub = IHubGatewayHandler(data);\n else if (what == \"poolManager\") poolManager = IPoolManagerGatewayHandler(data);\n else if (what == \"investmentManager\") investmentManager = IRequestManagerGatewayHandler(data);\n else if (what == \"balanceSheet\") balanceSheet = IBalanceSheetGatewayHandler(data);\n else revert FileUnrecognizedParam();\n\n emit File(what, data);\n }\n\n //----------------------------------------------------------------------------------------------\n // Handlers\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IMessageHandler\n function handle(uint16, bytes calldata message) external auth {\n MessageType kind = message.messageType();\n\n if (kind == MessageType.InitiateRecovery) {\n MessageLib.InitiateRecovery memory m = message.deserializeInitiateRecovery();\n gateway.initiateRecovery(m.centrifugeId, IAdapter(m.adapter.toAddress()), m.hash);\n } else if (kind == MessageType.DisputeRecovery) {\n MessageLib.DisputeRecovery memory m = message.deserializeDisputeRecovery();\n gateway.disputeRecovery(m.centrifugeId, IAdapter(m.adapter.toAddress()), m.hash);\n } else if (kind == MessageType.ScheduleUpgrade) {\n MessageLib.ScheduleUpgrade memory m = message.deserializeScheduleUpgrade();\n root.scheduleRely(m.target.toAddress());\n } else if (kind == MessageType.CancelUpgrade) {\n MessageLib.CancelUpgrade memory m = message.deserializeCancelUpgrade();\n root.cancelRely(m.target.toAddress());\n } else if (kind == MessageType.RecoverTokens) {\n MessageLib.RecoverTokens memory m = message.deserializeRecoverTokens();\n tokenRecoverer.recoverTokens(\n IRecoverable(m.target.toAddress()), m.token.toAddress(), m.tokenId, m.to.toAddress(), m.amount\n );\n } else if (kind == MessageType.RegisterAsset) {\n MessageLib.RegisterAsset memory m = message.deserializeRegisterAsset();\n hub.registerAsset(AssetId.wrap(m.assetId), m.decimals);\n } else if (kind == MessageType.NotifyPool) {\n poolManager.addPool(PoolId.wrap(MessageLib.deserializeNotifyPool(message).poolId));\n } else if (kind == MessageType.NotifyShareClass) {\n MessageLib.NotifyShareClass memory m = MessageLib.deserializeNotifyShareClass(message);\n poolManager.addShareClass(\n PoolId.wrap(m.poolId),\n ShareClassId.wrap(m.scId),\n m.name,\n m.symbol.toString(),\n m.decimals,\n m.salt,\n m.hook.toAddress()\n );\n } else if (kind == MessageType.NotifyPricePoolPerShare) {\n MessageLib.NotifyPricePoolPerShare memory m = MessageLib.deserializeNotifyPricePoolPerShare(message);\n poolManager.updatePricePoolPerShare(PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.price, m.timestamp);\n } else if (kind == MessageType.NotifyPricePoolPerAsset) {\n MessageLib.NotifyPricePoolPerAsset memory m = MessageLib.deserializeNotifyPricePoolPerAsset(message);\n poolManager.updatePricePoolPerAsset(\n PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), AssetId.wrap(m.assetId), m.price, m.timestamp\n );\n } else if (kind == MessageType.NotifyShareMetadata) {\n MessageLib.NotifyShareMetadata memory m = MessageLib.deserializeNotifyShareMetadata(message);\n poolManager.updateShareMetadata(\n PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.name, m.symbol.toString()\n );\n } else if (kind == MessageType.UpdateShareHook) {\n MessageLib.UpdateShareHook memory m = MessageLib.deserializeUpdateShareHook(message);\n poolManager.updateShareHook(PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.hook.toAddress());\n } else if (kind == MessageType.TransferShares) {\n MessageLib.TransferShares memory m = MessageLib.deserializeTransferShares(message);\n poolManager.handleTransferShares(\n PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.receiver.toAddress(), m.amount\n );\n } else if (kind == MessageType.UpdateRestriction) {\n MessageLib.UpdateRestriction memory m = MessageLib.deserializeUpdateRestriction(message);\n poolManager.updateRestriction(PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.payload);\n } else if (kind == MessageType.UpdateContract) {\n MessageLib.UpdateContract memory m = MessageLib.deserializeUpdateContract(message);\n poolManager.updateContract(\n PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.target.toAddress(), m.payload\n );\n } else if (kind == MessageType.DepositRequest) {\n MessageLib.DepositRequest memory m = message.deserializeDepositRequest();\n hub.depositRequest(\n PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.investor, AssetId.wrap(m.assetId), m.amount\n );\n } else if (kind == MessageType.RedeemRequest) {\n MessageLib.RedeemRequest memory m = message.deserializeRedeemRequest();\n hub.redeemRequest(\n PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.investor, AssetId.wrap(m.assetId), m.amount\n );\n } else if (kind == MessageType.CancelDepositRequest) {\n MessageLib.CancelDepositRequest memory m = message.deserializeCancelDepositRequest();\n hub.cancelDepositRequest(\n PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.investor, AssetId.wrap(m.assetId)\n );\n } else if (kind == MessageType.CancelRedeemRequest) {\n MessageLib.CancelRedeemRequest memory m = message.deserializeCancelRedeemRequest();\n hub.cancelRedeemRequest(\n PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.investor, AssetId.wrap(m.assetId)\n );\n } else if (kind == MessageType.FulfilledDepositRequest) {\n MessageLib.FulfilledDepositRequest memory m = message.deserializeFulfilledDepositRequest();\n investmentManager.fulfillDepositRequest(\n PoolId.wrap(m.poolId),\n ShareClassId.wrap(m.scId),\n m.investor.toAddress(),\n AssetId.wrap(m.assetId),\n m.assetAmount,\n m.shareAmount\n );\n } else if (kind == MessageType.FulfilledRedeemRequest) {\n MessageLib.FulfilledRedeemRequest memory m = message.deserializeFulfilledRedeemRequest();\n investmentManager.fulfillRedeemRequest(\n PoolId.wrap(m.poolId),\n ShareClassId.wrap(m.scId),\n m.investor.toAddress(),\n AssetId.wrap(m.assetId),\n m.assetAmount,\n m.shareAmount\n );\n } else if (kind == MessageType.FulfilledCancelDepositRequest) {\n MessageLib.FulfilledCancelDepositRequest memory m = message.deserializeFulfilledCancelDepositRequest();\n investmentManager.fulfillCancelDepositRequest(\n PoolId.wrap(m.poolId),\n ShareClassId.wrap(m.scId),\n m.investor.toAddress(),\n AssetId.wrap(m.assetId),\n m.cancelledAmount,\n m.cancelledAmount\n );\n } else if (kind == MessageType.FulfilledCancelRedeemRequest) {\n MessageLib.FulfilledCancelRedeemRequest memory m = message.deserializeFulfilledCancelRedeemRequest();\n investmentManager.fulfillCancelRedeemRequest(\n PoolId.wrap(m.poolId),\n ShareClassId.wrap(m.scId),\n m.investor.toAddress(),\n AssetId.wrap(m.assetId),\n m.cancelledShares\n );\n } else if (kind == MessageType.TriggerIssueShares) {\n MessageLib.TriggerIssueShares memory m = message.deserializeTriggerIssueShares();\n balanceSheet.triggerIssueShares(\n PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.who.toAddress(), m.shares\n );\n } else if (kind == MessageType.UpdateHoldingAmount) {\n MessageLib.UpdateHoldingAmount memory m = message.deserializeUpdateHoldingAmount();\n hub.updateHoldingAmount(\n PoolId.wrap(m.poolId),\n ShareClassId.wrap(m.scId),\n AssetId.wrap(m.assetId),\n m.amount,\n D18.wrap(m.pricePerUnit),\n m.isIncrease\n );\n } else if (kind == MessageType.UpdateShares) {\n MessageLib.UpdateShares memory m = message.deserializeUpdateShares();\n if (m.isIssuance) {\n hub.increaseShareIssuance(PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.shares);\n } else {\n hub.decreaseShareIssuance(PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.shares);\n }\n } else if (kind == MessageType.ApprovedDeposits) {\n MessageLib.ApprovedDeposits memory m = message.deserializeApprovedDeposits();\n investmentManager.approvedDeposits(\n PoolId.wrap(m.poolId),\n ShareClassId.wrap(m.scId),\n AssetId.wrap(m.assetId),\n m.assetAmount,\n D18.wrap(m.pricePoolPerAsset)\n );\n } else if (kind == MessageType.IssuedShares) {\n MessageLib.IssuedShares memory m = message.deserializeIssuedShares();\n investmentManager.issuedShares(\n PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.shareAmount, D18.wrap(m.pricePoolPerShare)\n );\n } else if (kind == MessageType.RevokedShares) {\n MessageLib.RevokedShares memory m = message.deserializeRevokedShares();\n investmentManager.revokedShares(\n PoolId.wrap(m.poolId),\n ShareClassId.wrap(m.scId),\n AssetId.wrap(m.assetId),\n m.assetAmount,\n m.shareAmount,\n D18.wrap(m.pricePoolPerShare)\n );\n } else if (kind == MessageType.TriggerSubmitQueuedShares) {\n MessageLib.TriggerSubmitQueuedShares memory m = message.deserializeTriggerSubmitQueuedShares();\n balanceSheet.submitQueuedShares(PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId));\n } else if (kind == MessageType.TriggerSubmitQueuedAssets) {\n MessageLib.TriggerSubmitQueuedAssets memory m = message.deserializeTriggerSubmitQueuedAssets();\n balanceSheet.submitQueuedAssets(PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), AssetId.wrap(m.assetId));\n } else if (kind == MessageType.SetQueue) {\n MessageLib.SetQueue memory m = message.deserializeSetQueue();\n balanceSheet.setQueue(PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.enabled);\n } else {\n revert InvalidMessage(uint8(kind));\n }\n }\n\n /// @inheritdoc IMessageProperties\n function isMessageRecovery(bytes calldata message) external pure returns (bool) {\n uint8 code = message.messageCode();\n return code == uint8(MessageType.InitiateRecovery) || code == uint8(MessageType.DisputeRecovery);\n }\n\n /// @inheritdoc IMessageProperties\n function messageLength(bytes calldata message) external pure returns (uint16) {\n return message.messageLength();\n }\n\n /// @inheritdoc IMessageProperties\n function messagePoolId(bytes calldata message) external pure returns (PoolId) {\n return message.messagePoolId();\n }\n}\n" + }, + "src/common/Root.sol": { + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {IAuth} from \"src/misc/interfaces/IAuth.sol\";\n\nimport {IRoot} from \"src/common/interfaces/IRoot.sol\";\n\n/// @title Root\n/// @notice Core contract that is a ward on all other deployed contracts.\n/// @dev Pausing can happen instantaneously, but relying on other contracts\n/// is restricted to the timelock set by the delay.\ncontract Root is Auth, IRoot {\n /// @dev To prevent filing a delay that would block any updates indefinitely\n uint256 internal constant MAX_DELAY = 4 weeks;\n\n bool public paused;\n uint256 public delay;\n mapping(address => uint256) public endorsements;\n mapping(address relyTarget => uint256 timestamp) public schedule;\n\n constructor(uint256 _delay, address deployer) Auth(deployer) {\n require(_delay <= MAX_DELAY, DelayTooLong());\n delay = _delay;\n }\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IRoot\n function file(bytes32 what, uint256 data) external auth {\n if (what == \"delay\") {\n require(data <= MAX_DELAY, DelayTooLong());\n delay = data;\n } else {\n revert FileUnrecognizedParam();\n }\n emit File(what, data);\n }\n\n /// @inheritdoc IRoot\n function endorse(address user) external auth {\n endorsements[user] = 1;\n emit Endorse(user);\n }\n\n /// @inheritdoc IRoot\n function veto(address user) external auth {\n endorsements[user] = 0;\n emit Veto(user);\n }\n\n /// @inheritdoc IRoot\n function endorsed(address user) external view returns (bool) {\n return endorsements[user] == 1;\n }\n\n //----------------------------------------------------------------------------------------------\n // Pause management\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IRoot\n function pause() external auth {\n paused = true;\n emit Pause();\n }\n\n /// @inheritdoc IRoot\n function unpause() external auth {\n paused = false;\n emit Unpause();\n }\n\n //----------------------------------------------------------------------------------------------\n // Timelocked ward management\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IRoot\n function scheduleRely(address target) external auth {\n schedule[target] = block.timestamp + delay;\n emit ScheduleRely(target, schedule[target]);\n }\n\n /// @inheritdoc IRoot\n function cancelRely(address target) external auth {\n require(schedule[target] != 0, TargetNotScheduled());\n schedule[target] = 0;\n emit CancelRely(target);\n }\n\n /// @inheritdoc IRoot\n function executeScheduledRely(address target) external {\n require(schedule[target] != 0, TargetNotScheduled());\n require(schedule[target] <= block.timestamp, TargetNotReady());\n\n wards[target] = 1;\n emit Rely(target);\n\n schedule[target] = 0;\n }\n\n //----------------------------------------------------------------------------------------------\n // External contract ward management\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IRoot\n function relyContract(address target, address user) external auth {\n IAuth(target).rely(user);\n emit RelyContract(target, user);\n }\n\n /// @inheritdoc IRoot\n function denyContract(address target, address user) external auth {\n IAuth(target).deny(user);\n emit DenyContract(target, user);\n }\n}\n" + }, + "src/common/TokenRecoverer.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {IRecoverable} from \"src/misc/interfaces/IRecoverable.sol\";\n\nimport {IRoot} from \"src/common/interfaces/IRoot.sol\";\nimport {ITokenRecoverer} from \"src/common/interfaces/ITokenRecoverer.sol\";\nimport {IRecoverable} from \"src/misc/interfaces/IRecoverable.sol\";\n\ncontract TokenRecoverer is Auth, ITokenRecoverer {\n IRoot public immutable root;\n\n constructor(IRoot root_, address deployer) Auth(deployer) {\n root = root_;\n }\n\n /// @notice inheritdoc ITokenRecoverer\n function recoverTokens(IRecoverable target, address token, uint256 tokenId, address to, uint256 amount)\n external\n auth\n {\n root.relyContract(address(target), address(this));\n\n if (tokenId == 0) {\n target.recoverTokens(token, to, amount);\n } else {\n target.recoverTokens(token, tokenId, to, amount);\n }\n\n root.denyContract(address(target), address(this));\n\n emit RecoverTokens(target, token, tokenId, to, amount);\n }\n}\n" + }, + "src/common/adapters/AxelarAdapter.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {\n IAxelarAdapter,\n IAdapter,\n IAxelarGateway,\n IAxelarGasService,\n AxelarSource,\n AxelarDestination,\n IAxelarExecutable\n} from \"src/common/interfaces/IAxelarAdapter.sol\";\nimport {IMessageHandler} from \"src/common/interfaces/IMessageHandler.sol\";\n\n/// @title Axelar Adapter\n/// @notice Routing contract that integrates with an Axelar Gateway\ncontract AxelarAdapter is Auth, IAxelarAdapter {\n using CastLib for *;\n\n IMessageHandler public immutable gateway;\n IAxelarGateway public immutable axelarGateway;\n IAxelarGasService public immutable axelarGasService;\n\n mapping(string axelarId => AxelarSource) public sources;\n mapping(uint16 centrifugeId => AxelarDestination) public destinations;\n\n constructor(IMessageHandler gateway_, address axelarGateway_, address axelarGasService_, address deployer)\n Auth(deployer)\n {\n gateway = gateway_;\n axelarGateway = IAxelarGateway(axelarGateway_);\n axelarGasService = IAxelarGasService(axelarGasService_);\n }\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IAxelarAdapter\n function file(bytes32 what, string calldata axelarId, uint16 centrifugeId, string calldata source) external auth {\n if (what == \"sources\") sources[axelarId] = AxelarSource(centrifugeId, keccak256(bytes(source)));\n else revert FileUnrecognizedParam();\n emit File(what, axelarId, centrifugeId, source);\n }\n\n /// @inheritdoc IAxelarAdapter\n function file(bytes32 what, uint16 centrifugeId, string calldata axelarId, string calldata destination)\n external\n auth\n {\n if (what == \"destinations\") destinations[centrifugeId] = AxelarDestination(axelarId, destination);\n else revert FileUnrecognizedParam();\n emit File(what, centrifugeId, axelarId, destination);\n }\n\n //----------------------------------------------------------------------------------------------\n // Incoming\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IAxelarExecutable\n function execute(\n bytes32 commandId,\n string calldata sourceAxelarId,\n string calldata sourceAddress,\n bytes calldata payload\n ) public {\n AxelarSource memory source = sources[sourceAxelarId];\n require(\n source.addressHash != bytes32(\"\") && source.addressHash == keccak256(bytes(sourceAddress)), InvalidAddress()\n );\n\n require(\n axelarGateway.validateContractCall(commandId, sourceAxelarId, sourceAddress, keccak256(payload)),\n NotApprovedByGateway()\n );\n\n gateway.handle(source.centrifugeId, payload);\n }\n\n //----------------------------------------------------------------------------------------------\n // Outgoing\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IAdapter\n function send(uint16 centrifugeId, bytes calldata payload, uint256, /* gasLimit */ address refund)\n external\n payable\n returns (bytes32 adapterData)\n {\n require(msg.sender == address(gateway), NotGateway());\n AxelarDestination memory destination = destinations[centrifugeId];\n require(bytes(destination.axelarId).length != 0, UnknownChainId());\n\n axelarGasService.payNativeGasForContractCall{value: msg.value}(\n address(this), destination.axelarId, destination.addr, payload, refund\n );\n\n axelarGateway.callContract(destination.axelarId, destination.addr, payload);\n\n adapterData = bytes32(\"\");\n }\n\n /// @inheritdoc IAdapter\n function estimate(uint16 centrifugeId, bytes calldata payload, uint256 gasLimit) public view returns (uint256) {\n AxelarDestination memory destination = destinations[centrifugeId];\n return axelarGasService.estimateGasFee(destination.axelarId, destination.addr, payload, gasLimit, bytes(\"\"));\n }\n}\n" + }, + "src/common/adapters/WormholeAdapter.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {IMessageHandler} from \"src/common/interfaces/IMessageHandler.sol\";\nimport {\n IWormholeAdapter,\n IAdapter,\n IWormholeRelayer,\n IWormholeDeliveryProvider,\n IWormholeReceiver,\n WormholeSource,\n WormholeDestination\n} from \"src/common/interfaces/IWormholeAdapter.sol\";\n\n/// @title Wormhole Adapter\n/// @notice Routing contract that integrates with the Wormhole Relayer service\ncontract WormholeAdapter is Auth, IWormholeAdapter {\n using CastLib for bytes32;\n\n uint16 public immutable localWormholeId;\n IMessageHandler public immutable gateway;\n IWormholeRelayer public immutable relayer;\n\n mapping(uint16 wormholeId => WormholeSource) public sources;\n mapping(uint16 centrifugeId => WormholeDestination) public destinations;\n\n constructor(IMessageHandler gateway_, address relayer_, address deployer) Auth(deployer) {\n gateway = gateway_;\n relayer = IWormholeRelayer(relayer_);\n\n IWormholeDeliveryProvider deliveryProvider = IWormholeDeliveryProvider(relayer.getDefaultDeliveryProvider());\n localWormholeId = deliveryProvider.chainId();\n }\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IWormholeAdapter\n function file(bytes32 what, uint16 centrifugeId, uint16 wormholeId, address addr) external auth {\n if (what == \"sources\") sources[wormholeId] = WormholeSource(centrifugeId, addr);\n else if (what == \"destinations\") destinations[centrifugeId] = WormholeDestination(wormholeId, addr);\n else revert FileUnrecognizedParam();\n emit File(what, centrifugeId, wormholeId, addr);\n }\n\n //----------------------------------------------------------------------------------------------\n // Incoming\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IWormholeReceiver\n function receiveWormholeMessages(\n bytes memory payload,\n bytes[] memory, /* additionalVaas */\n bytes32 sourceAddress,\n uint16 sourceWormholeId,\n bytes32 /* deliveryHash */\n ) external payable {\n WormholeSource memory source = sources[sourceWormholeId];\n require(source.addr != address(0) && source.addr == sourceAddress.toAddressLeftPadded(), InvalidSource());\n require(msg.sender == address(relayer), NotWormholeRelayer());\n\n gateway.handle(source.centrifugeId, payload);\n }\n\n //----------------------------------------------------------------------------------------------\n // Outgoing\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IAdapter\n function send(uint16 centrifugeId, bytes calldata payload, uint256 gasLimit, address refund)\n external\n payable\n returns (bytes32 adapterData)\n {\n require(msg.sender == address(gateway), NotGateway());\n WormholeDestination memory destination = destinations[centrifugeId];\n require(destination.wormholeId != 0, UnknownChainId());\n\n uint64 sequence = relayer.sendPayloadToEvm{value: msg.value}(\n destination.wormholeId, destination.addr, payload, 0, gasLimit, localWormholeId, refund\n );\n\n adapterData = bytes32(bytes8(sequence));\n }\n\n /// @inheritdoc IAdapter\n function estimate(uint16 centrifugeId, bytes calldata, uint256 gasLimit)\n public\n view\n returns (uint256 nativePriceQuote)\n {\n (nativePriceQuote,) = relayer.quoteEVMDeliveryPrice(destinations[centrifugeId].wormholeId, 0, gasLimit);\n }\n}\n" + }, + "src/common/interfaces/IAdapter.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IAuth} from \"src/misc/interfaces/IAuth.sol\";\n\ninterface IAdapter is IAuth {\n error NotGateway();\n error UnknownChainId();\n\n /// @notice Send a payload to the destination chain\n function send(uint16 centrifugeId, bytes calldata payload, uint256 gasLimit, address refund)\n external\n payable\n returns (bytes32 adapterData);\n\n /// @notice Estimate the total cost in native gas tokens\n function estimate(uint16 centrifugeId, bytes calldata payload, uint256 gasLimit) external view returns (uint256);\n}\n" + }, + "src/common/interfaces/IAxelarAdapter.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IAdapter} from \"src/common/interfaces/IAdapter.sol\";\n\n// From https://github.com/axelarnetwork/axelar-cgp-solidity/blob/main/contracts/interfaces/IAxelarGateway.sol\ninterface IAxelarGateway {\n function callContract(string calldata destinationChain, string calldata contractAddress, bytes calldata payload)\n external;\n\n function validateContractCall(\n bytes32 commandId,\n string calldata sourceChain,\n string calldata sourceAddress,\n bytes32 payloadHash\n ) external returns (bool);\n}\n\ninterface IAxelarGasService {\n // From\n // https://github.com/axelarnetwork/axelar-gmp-sdk-solidity/blob/00682b6c3db0cc922ec0c4ea3791852c93d7ae31/contracts/gas-estimation/InterchainGasEstimation.sol#L48\n function estimateGasFee(\n string calldata destinationChain,\n string calldata destinationAddress,\n bytes calldata payload,\n uint256 executionGasLimit,\n bytes calldata params\n ) external view returns (uint256 gasEstimate);\n\n // From https://github.com/axelarnetwork/axelar-cgp-solidity/blob/main/contracts/interfaces/IAxelarGasService.sol\n function payNativeGasForContractCall(\n address sender,\n string calldata destinationChain,\n string calldata destinationAddress,\n bytes calldata payload,\n address refundAddress\n ) external payable;\n}\n\n// From\n// https://github.com/axelarnetwork/axelar-gmp-sdk-solidity/blob/00682b6c3db0cc922ec0c4ea3791852c93d7ae31/contracts/interfaces/IAxelarExecutable.sol#L14\ninterface IAxelarExecutable {\n /**\n * @dev Thrown when a function is called with an invalid address.\n */\n error InvalidAddress();\n\n /**\n * @dev Thrown when the call is not approved by the Axelar Gateway.\n */\n error NotApprovedByGateway();\n\n /**\n * @notice Executes the specified command sent from another chain.\n * @dev This function is called by the Axelar Gateway to carry out cross-chain commands.\n * Reverts if the call is not approved by the gateway or other checks fail.\n * @param commandId The identifier of the command to execute.\n * @param sourceChain The name of the source chain from where the command originated.\n * @param sourceAddress The address on the source chain that sent the command.\n * @param payload The payload of the command to be executed. This typically includes the function selector and\n * encoded arguments.\n */\n function execute(\n bytes32 commandId,\n string calldata sourceChain,\n string calldata sourceAddress,\n bytes calldata payload\n ) external;\n}\n\nstruct AxelarSource {\n uint16 centrifugeId;\n bytes32 addressHash;\n}\n\nstruct AxelarDestination {\n string axelarId;\n string addr;\n}\n\ninterface IAxelarAdapter is IAdapter, IAxelarExecutable {\n event File(bytes32 indexed what, string axelarId, uint16 centrifugeId, string source);\n event File(bytes32 indexed what, uint16 centrifugeId, string axelarId, string destination);\n\n error FileUnrecognizedParam();\n\n function file(bytes32 what, string calldata axelarId, uint16 centrifugeId, string calldata source) external;\n function file(bytes32 what, uint16 centrifugeId, string calldata axelarId, string calldata destination) external;\n}\n" + }, + "src/common/interfaces/IGasService.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\ninterface IGasService {\n /// @notice Gas limit for the execution cost of an individual message in a remote chain.\n /// @dev NOTE: In the future we could want to dispatch:\n /// - by destination chain (for non-EVM chains)\n /// - by message type\n /// - by inspecting the payload checking different subsmessages that alter the endpoint processing\n /// @param centrifugeId Where to the cost is defined\n /// @param message Individual message\n /// @return Estimated cost in WEI units\n function gasLimit(uint16 centrifugeId, bytes calldata message) external view returns (uint128);\n\n /// @notice Gas limit for the execution cost of a batch in a remote chain.\n /// @param centrifugeId Where to the cost is defined\n /// @return Max cost in WEI units\n function maxBatchSize(uint16 centrifugeId) external view returns (uint128);\n}\n" + }, + "src/common/interfaces/IGateway.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IRecoverable} from \"src/misc/interfaces/IRecoverable.sol\";\n\nimport {IGatewayHandler} from \"src/common/interfaces/IGatewayHandlers.sol\";\nimport {IMessageHandler} from \"src/common/interfaces/IMessageHandler.sol\";\nimport {IMessageSender} from \"src/common/interfaces/IMessageSender.sol\";\nimport {IAdapter} from \"src/common/interfaces/IAdapter.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\n\nuint8 constant MAX_ADAPTER_COUNT = 8;\n\n/// @notice Interface for dispatch-only gateway\ninterface IGateway is IMessageHandler, IMessageSender, IGatewayHandler {\n /// @dev Each adapter struct is packed with the quorum to reduce SLOADs on handle\n struct Adapter {\n /// @notice Starts at 1 and maps to id - 1 as the index on the adapters array\n uint8 id;\n /// @notice Number of votes required for a message to be executed\n uint8 quorum;\n /// @notice Each time the quorum is decreased, a new session starts which invalidates old votes\n uint64 activeSessionId;\n }\n\n struct InboundBatch {\n /// @dev Counts are stored as integers (instead of boolean values) to accommodate duplicate\n /// messages (e.g. two investments from the same user with the same amount) being\n /// processed in parallel. The entire struct is packed in a single bytes32 slot.\n /// Max uint16 = 65,535 so at most 65,535 duplicate messages can be processed in parallel.\n uint16[MAX_ADAPTER_COUNT] votes;\n /// @notice Each time adapters are updated, a new session starts which invalidates old votes\n uint64 sessionId;\n bytes pendingBatch;\n }\n\n struct Funds {\n /// @notice Funds associated to pay for sending messages\n /// @dev Overflows with type(uint64).max / 10**18 = 7.923 × 10^10 ETH\n uint96 value;\n /// @notice Address where to refund the remaining gas\n IRecoverable refund;\n }\n\n // Used to bypass stack too deep issue\n struct SendData {\n bytes32 batchHash;\n bytes32 payloadId;\n uint256[] gasCost;\n }\n\n struct Underpaid {\n uint128 counter;\n uint128 gasLimit;\n }\n\n // --- Events ---\n event PrepareMessage(uint16 indexed centrifugeId, PoolId poolId, bytes message);\n event UnderpaidBatch(uint16 indexed centrifugeId, bytes batch);\n event RepayBatch(uint16 indexed centrifugeId, bytes batch);\n event SendBatch(\n uint16 indexed centrifugeId,\n bytes32 indexed payloadId,\n bytes batch,\n IAdapter adapter,\n bytes32 adapterData,\n address refund\n );\n event SendProof(\n uint16 indexed centrifugeId, bytes32 indexed payloadId, bytes32 batchHash, IAdapter adapter, bytes32 adapterData\n );\n event HandleBatch(uint16 indexed centrifugeId, bytes32 indexed payloadId, bytes batch, IAdapter adapter);\n event HandleProof(uint16 indexed centrifugeId, bytes32 indexed payloadId, bytes32 batchHash, IAdapter adapter);\n event ExecuteMessage(uint16 indexed centrifugeId, bytes message);\n event FailMessage(uint16 indexed centrifugeId, bytes message, bytes error);\n\n event RecoverMessage(IAdapter adapter, bytes message);\n event RecoverProof(IAdapter adapter, bytes32 batchHash);\n event InitiateRecovery(uint16 centrifugeId, bytes32 batchHash, IAdapter adapter);\n event DisputeRecovery(uint16 centrifugeId, bytes32 batchHash, IAdapter adapter);\n event ExecuteRecovery(uint16 centrifugeId, bytes message, IAdapter adapter);\n\n event File(bytes32 indexed what, uint16 centrifugeId, IAdapter[] adapters);\n event File(bytes32 indexed what, address addr);\n\n event SetRefundAddress(PoolId poolId, IRecoverable refund);\n event SubsidizePool(PoolId indexed poolId, address indexed sender, uint256 amount);\n\n /// @notice Dispatched when the `what` parameter of `file()` is not supported by the implementation.\n error FileUnrecognizedParam();\n\n /// @notice Dispatched when the batch is ended without starting it.\n error NoBatched();\n\n /// @notice Dispatched when the gateway is paused.\n error Paused();\n\n /// @notice Dispatched when the gateway is configured with a number of adapter exceeding the maximum.\n error ExceedsMax();\n\n /// @notice Dispatched when the gateway is configured with an empty adapter set.\n error EmptyAdapterSet();\n\n /// @notice Dispatched when the gateway is configured with duplicate adapters.\n error NoDuplicatesAllowed();\n\n /// @notice Dispatched when the gateway tries to handle a message from an adaptet not contained in the adapter set.\n error InvalidAdapter();\n\n /// @notice Dispatched when the gateway tries to recover a recovery message, which is not allowed.\n error RecoveryPayloadRecovered();\n\n /// @notice Dispatched when the gateway tries to handle a proof from a non proof adapter.\n error NonProofAdapter();\n\n /// @notice Dispatched when the gateway tries to handle a batch from a non message adapter.\n error NonBatchAdapter();\n\n /// @notice Dispatched when a recovery message is executed without being initiated.\n error RecoveryNotInitiated();\n\n /// @notice Dispatched when a recovery message is executed without waiting the challenge period.\n error RecoveryChallengePeriodNotEnded();\n\n /// @notice Dispatched when a the gateway tries to send an empty message.\n error EmptyMessage();\n\n /// @notice Dispatched when a the gateway has not enough fuel to send a message.\n /// Only dispatched in PayTransaction method\n error NotEnoughTransactionGas();\n\n /// @notice Dispatched when a message that has not failed is retried.\n error NotFailedMessage();\n\n /// @notice Dispatched when a batch that has not been underpaid is repaid.\n error NotUnderpaidBatch();\n\n /// @notice Dispatched when a batch is repaid with insufficient funds.\n error InsufficientFundsForRepayment();\n\n /// @notice Dispatched when a message is added to a batch that causes it to exceed the max batch size.\n error ExceedsMaxBatchSize();\n\n /// @notice Dispatched when a refund address is not set.\n error RefundAddressNotSet();\n\n // --- Administration ---\n /// @notice Used to update an array of addresses ( state variable ) on very rare occasions.\n /// @dev Currently it is used to update the supported adapters.\n /// @param what The name of the variable to be updated.\n /// @param centrifugeId Chain where the adapters are associated to.\n /// @param value New addresses.\n function file(bytes32 what, uint16 centrifugeId, IAdapter[] calldata value) external;\n\n /// @notice Used to update an address ( state variable ) on very rare occasions.\n /// @dev Currently used to update addresses of contract instances.\n /// @param what The name of the variable to be updated.\n /// @param data New address.\n function file(bytes32 what, address data) external;\n\n /// @notice Repay an underpaid batch. Send unused funds to subsidy pot of the pool.\n function repay(uint16 centrifugeId, bytes memory batch) external payable;\n\n /// @notice Retry a failed message.\n function retry(uint16 centrifugeId, bytes memory message) external;\n\n /// @notice Set the refund address for message associated to a poolId\n function setRefundAddress(PoolId poolId, IRecoverable refund) external;\n\n /// @notice Pay upfront to later be able to subsidize messages associated to a pool\n function subsidizePool(PoolId poolId) external payable;\n\n /// @notice Prepays for the TX cost for sending the messages through the adapters\n /// Currently being called from Vault Router only.\n /// In order to prepay, the method MUST be called with `msg.value`.\n /// Called is assumed to have called IGateway.estimate before calling this.\n function payTransaction(address payer) external payable;\n\n /// @notice Initialize batching message\n function startBatching() external;\n\n /// @notice Finalize batching messages and send the resulting batch message\n function endBatching() external;\n\n /// @notice Execute message recovery. After the challenge period, the recovery can be executed.\n /// If a malign adapter initiates message recovery,\n /// governance can dispute and immediately cancel the recovery, using any other valid adapter.\n ///\n /// Only 1 recovery can be outstanding per message hash. If multiple adapters fail at the same time,\n /// these will need to be recovered serially (increasing the challenge period for each failed adapter).\n /// @param centrifugeId Chain where the adapter is configured for\n /// @param adapter Adapter's address that the recovery is targeting\n /// @param message Hash of the message to be recovered\n function executeRecovery(uint16 centrifugeId, IAdapter adapter, bytes calldata message) external;\n\n // --- Helpers ---\n /// @notice A view method of the current quorum.abi\n /// @dev Quorum shows the amount of votes needed in order for a message to be dispatched further.\n /// The quorum is taken from the first adapter which is always the length of active adapters.\n /// @param centrifugeId Chain where the adapter is configured for\n /// return Needed amount\n function quorum(uint16 centrifugeId) external view returns (uint8);\n\n /// @notice Gets the current active routers session id.\n /// @dev When the adapters are updated with new ones,\n /// each new set of adapters has their own sessionId.\n /// Currently it uses sessionId of the previous set and\n /// increments it by 1. The idea of an activeSessionId is\n /// to invalidate any incoming messages from previously used adapters.\n /// @param centrifugeId Chain where the adapter is configured for\n function activeSessionId(uint16 centrifugeId) external view returns (uint64);\n\n /// @notice Counts how many times each incoming messages has been received per adapter.\n /// @dev It supports parallel messages ( duplicates ). That means that the incoming messages could be\n /// the result of two or more independ request from the user of the same type.\n /// i.e. Same user would like to deposit same underlying asset with the same amount more then once.\n /// @param centrifugeId Chain where the adapter is configured for\n /// @param batchHash The hash value of the incoming batch message.\n function votes(uint16 centrifugeId, bytes32 batchHash) external view returns (uint16[MAX_ADAPTER_COUNT] memory);\n\n /// @notice Used to calculate overall cost for bridging a payload on the first adapter and settling\n /// on the destination chain and bridging its payload proofs on n-1 adapter\n /// and settling on the destination chain.\n /// @param payload Used in gas cost calculations.\n /// @dev Currenly the payload is not taken into consideration.\n /// @return total Total cost for sending one message and corresponding proofs on through all adapters\n function estimate(uint16 centrifugeId, bytes calldata payload) external view returns (uint256 total);\n\n /// @notice Returns the address of the adapter at the given id.\n /// @param centrifugeId Chain where the adapter is configured for\n function adapters(uint16 centrifugeId, uint256 id) external view returns (IAdapter);\n\n /// @notice Returns the timestamp when the given recovery can be executed.\n /// @param centrifugeId Chain where the adapter is configured for\n function recoveries(uint16 centrifugeId, IAdapter adapter, bytes32 batchHash)\n external\n view\n returns (uint256 timestamp);\n\n /// @notice Returns the current gateway batching level.\n function isBatching() external view returns (bool);\n}\n" + }, + "src/common/interfaces/IGatewayHandlers.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {D18} from \"src/misc/types/D18.sol\";\n\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {IAdapter} from \"src/common/interfaces/IAdapter.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\n\n/// -----------------------------------------------------\n/// Common Handlers\n/// -----------------------------------------------------\n/// @notice Interface for Gateway methods called by messages\ninterface IGatewayHandler {\n /// @notice Initialize the recovery of a payload.\n /// @param centrifugeId Chain where the adapter is configured for\n /// @param adapter Adapter that the recovery was targeting\n /// @param payloadHash Hash of the payload being disputed\n function initiateRecovery(uint16 centrifugeId, IAdapter adapter, bytes32 payloadHash) external;\n\n /// @notice Cancel the recovery of a payload.\n /// @param centrifugeId Chain where the adapter is configured for\n /// @param adapter Adapter that the recovery was targeting\n /// @param payloadHash Hash of the payload being disputed\n function disputeRecovery(uint16 centrifugeId, IAdapter adapter, bytes32 payloadHash) external;\n}\n\n/// -----------------------------------------------------\n/// CP Handlers\n/// -----------------------------------------------------\n\n/// @notice Interface for CP methods called by messages\ninterface IHubGatewayHandler {\n /// @notice Tells that an asset was already registered in CV, in order to perform the corresponding register.\n function registerAsset(AssetId assetId, uint8 decimals) external;\n\n /// @notice Perform a deposit that was requested from CV.\n function depositRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId depositAssetId, uint128 amount)\n external;\n\n /// @notice Perform a redeem that was requested from CV.\n function redeemRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId payoutAssetId, uint128 amount)\n external;\n\n /// @notice Perform a deposit cancellation that was requested from CV.\n function cancelDepositRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId depositAssetId)\n external;\n\n /// @notice Perform a redeem cancellation that was requested from CV.\n function cancelRedeemRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId payoutAssetId) external;\n\n /// @notice Update a holding by request from CAL.\n function updateHoldingAmount(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n uint128 amount,\n D18 pricePoolPerAsset,\n bool isIncrease\n ) external;\n\n /// @notice Increases the total issuance of shares by request from CAL.\n function increaseShareIssuance(PoolId poolId, ShareClassId scId, uint128 amount) external;\n\n /// @notice Decreases the total issuance of shares by request from CAL.\n function decreaseShareIssuance(PoolId poolId, ShareClassId scId, uint128 amount) external;\n}\n\n/// -----------------------------------------------------\n/// CV Handlers\n/// -----------------------------------------------------\n\n/// @notice Interface for CV methods related to pools called by messages\ninterface IPoolManagerGatewayHandler {\n /// @notice New pool details from an existing Centrifuge pool are added.\n /// @dev The function can only be executed by the gateway contract.\n function addPool(PoolId poolId) external;\n\n /// @notice New share class details from an existing Centrifuge pool are added.\n /// @dev The function can only be executed by the gateway contract.\n function addShareClass(\n PoolId poolId,\n ShareClassId scId,\n string memory tokenName,\n string memory tokenSymbol,\n uint8 decimals,\n bytes32 salt,\n address hook\n ) external;\n\n /// @notice Updates the tokenName and tokenSymbol of a share class token\n /// @dev The function can only be executed by the gateway contract.\n function updateShareMetadata(PoolId poolId, ShareClassId scId, string memory tokenName, string memory tokenSymbol)\n external;\n\n /// @notice Updates the price of a share class token, i.e. the factor of pool currency amount per share class token\n /// @dev The function can only be executed by the gateway contract.\n /// @param poolId The pool id\n /// @param scId The share class id\n /// @param price The price of pool currency per share class token as factor.\n /// @param computedAt The timestamp when the price was computed\n function updatePricePoolPerShare(PoolId poolId, ShareClassId scId, uint128 price, uint64 computedAt) external;\n\n /// @notice Updates the price of an asset, i.e. the factor of pool currency amount per asset unit\n /// @dev The function can only be executed by the gateway contract.\n /// @param poolId The pool id\n /// @param scId The share class id\n /// @param assetId The asset id\n /// @param poolPerAsset The price of pool currency per asset unit as factor.\n /// @param computedAt The timestamp when the price was computed\n function updatePricePoolPerAsset(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n uint128 poolPerAsset,\n uint64 computedAt\n ) external;\n\n /// @notice Updates the hook of a share class token\n /// @param poolId The centrifuge pool id\n /// @param scId The share class id\n /// @param hook The new hook addres\n function updateShareHook(PoolId poolId, ShareClassId scId, address hook) external;\n\n /// @notice Updates the restrictions on a share class token for a specific user\n /// @param poolId The centrifuge pool id\n /// @param scId The share class id\n /// @param update The restriction update in the form of a bytes array indicating\n /// the restriction to be updated, the user to be updated, and a validUntil timestamp.\n function updateRestriction(PoolId poolId, ShareClassId scId, bytes memory update) external;\n\n /// @notice Mints share class tokens to a recipient\n /// @dev The function can only be executed internally or by the gateway contract.\n function handleTransferShares(PoolId poolId, ShareClassId scId, address destinationAddress, uint128 amount)\n external;\n\n /// @notice Updates the target address. Generic update function from CP to CV\n /// @param poolId The centrifuge pool id\n /// @param scId The share class id\n /// @param target The target address to be called\n /// @param update The payload to be processed by the target address\n function updateContract(PoolId poolId, ShareClassId scId, address target, bytes memory update) external;\n}\n\n/// @notice Interface for CV methods related to async investments called by messages\ninterface IRequestManagerGatewayHandler {\n /// @notice Signal from the Hub that an asynchronous investment order has been approved\n ///\n /// @dev This message needs to trigger making the asset amounts available to the pool-share-class.\n function approvedDeposits(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n uint128 assetAmount,\n D18 pricePoolPerAsset\n ) external;\n\n /// @notice Signal from the Hub that an asynchronous investment order has been finalized. Shares have been issued.\n ///\n /// @dev This message needs to trigger minting the new amount of shares.\n function issuedShares(PoolId poolId, ShareClassId scId, uint128 shareAmount, D18 pricePoolPerShare) external;\n\n /// @notice Signal from the Hub that an asynchronous redeem order has been finalized.\n ///\n /// @dev This messages needs to trigger reserving the asset amount for claims of redemptions by users.\n function revokedShares(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n uint128 assetAmount,\n uint128 shareAmount,\n D18 pricePoolPerShare\n ) external;\n\n // --- Deposits ---\n /// @notice Fulfills pending deposit requests after successful epoch execution on CP.\n /// The amount of shares that can be claimed by the user is minted and moved to the escrow contract.\n /// The MaxMint bookkeeping value is updated.\n /// The request fulfillment can be partial.\n /// @dev The shares in the escrow are reserved for the user and are transferred to the user on deposit\n /// and mint calls.\n function fulfillDepositRequest(\n PoolId poolId,\n ShareClassId scId,\n address user,\n AssetId assetId,\n uint128 assets,\n uint128 shares\n ) external;\n\n /// @notice Fulfills deposit request cancellation after successful epoch execution on CP.\n /// The amount of assets that can be claimed by the user is locked in the escrow contract.\n /// Updates claimableCancelDepositRequest bookkeeping value. The cancellation order execution can be\n /// partial.\n /// @dev The assets in the escrow are reserved for the user and are transferred to the user during\n /// claimCancelDepositRequest calls.\n /// `fulfillment` represents the decrease in `pendingDepositRequest`.\n /// This is a separate parameter from `assets` since there can be some precision loss when calculating this,\n /// which would lead to having dust in the pendingDepositRequest value and\n /// never closing out the request even after it is technically fulfilled.\n ///\n /// Example:\n /// User deposits 100 units of the vaults underlying asset.\n /// - At some point they make cancellation request. The order in which is not guaranteed\n /// Both requests arrive at CentrifugeChain. If the cancellation is first then all of the\n /// deposited amount will be cancelled.\n ///\n /// - There is the case where the deposit event is first and it gets completely fulfilled then\n /// No amount of the deposited asset will be cancelled.\n ///\n /// - There is the case where partially the deposit request is fulfilled. Let's say 40 units.\n /// Then the cancel request arrives.\n /// The remaining amount of deposited funds which is 60 units will cancelled.\n /// There is a scenario where the deposit funds might different from the pool currency so some\n /// swapping might happen. Either during this swapping or some fee collection or rounding there will be\n /// difference between the actual amount that will be returned to the user.\n /// `fulfillment` in this case will be 60 units but assets will be some lower amount because of the\n /// aforementioned reasons\n /// Let's assume the `asset` is 59. The user will be able to take back these 59 but\n /// in order to not let any dust, we use `fulfillment` in our calculations.\n ///\n /// `pendingDepositRequest` not necessary gets zeroed during this cancellation event.\n /// When CentrifugeChain process the cancel event on its side, part of the deposit might be fulfilled.\n /// In such case the chain will send two messages, one `fulfillDepositRequest` and one\n /// `fulfillCancelDepositRequest`. In the example above, given the 100 units\n /// deposited, 40 units are fulfilled and 60 can be cancelled.\n /// The two messages sent from CentrifugeChain are not guaranteed to arrive in order.\n ///\n /// Assuming first is the `fulfillCancelDepositRequest` the `pendingDepositRequest` here will be reduced to\n /// 60 units only. Then the `fulfillCancelDepositRequest` arrives with `fulfillment` 60. This amount is\n /// removed from `pendingDepositRequests`. Since there are not more pendingDepositRequest` the\n /// `pendingCancelDepositRequest` gets deleted.\n ///\n /// Assuming first the `fulfillCancelDepositRequest` arrives then the `pendingDepositRequest` will be 100.\n /// `fulfillment` is 60 so we are left with `pendingDepositRequest` equals to 40 ( 100 - 60 ).\n /// Then the second message arrives which is `fulfillDepositRequest`. ( Check `fulfillDepositRequest`\n /// implementation for details.)\n /// When it arrives the `pendingDepositRequest` is 40 and the assets is 40\n /// so there are no more `pendingDepositRequest` and right there the `pendingCancelDepositRequest will be\n /// deleted.\n function fulfillCancelDepositRequest(\n PoolId poolId,\n ShareClassId scId,\n address user,\n AssetId assetId,\n uint128 assets,\n uint128 fulfillment\n ) external;\n\n // --- Redeems ---\n /// @notice Fulfills pending redeem requests after successful epoch execution on CP.\n /// The amount of redeemed shares is burned. The amount of assets that can be claimed by the user in\n /// return is locked in the escrow contract. The MaxWithdraw bookkeeping value is updated.\n /// The request fulfillment can be partial.\n /// @dev The assets in the escrow are reserved for the user and are transferred to the user on redeem\n /// and withdraw calls.\n function fulfillRedeemRequest(\n PoolId poolId,\n ShareClassId scId,\n address user,\n AssetId assetId,\n uint128 assets,\n uint128 shares\n ) external;\n\n /// @notice Fulfills redeem request cancellation after successful epoch execution on CP.\n /// The amount of shares that can be claimed by the user is locked in the escrow contract.\n /// Updates claimableCancelRedeemRequest bookkeeping value. The cancellation order execution can also be\n /// partial.\n /// @dev The shares in the escrow are reserved for the user and are transferred to the user during\n /// claimCancelRedeemRequest calls.\n function fulfillCancelRedeemRequest(PoolId poolId, ShareClassId scId, address user, AssetId assetId, uint128 shares)\n external;\n}\n\n/// @notice Interface for CV methods related to epoch called by messages\ninterface IBalanceSheetGatewayHandler {\n function triggerDeposit(PoolId poolId, ShareClassId scId, AssetId assetId, address provider, uint128 amount)\n external;\n\n function triggerWithdraw(PoolId poolId, ShareClassId scId, AssetId assetId, address receiver, uint128 amount)\n external;\n\n function triggerIssueShares(PoolId poolId, ShareClassId scId, address to, uint128 shares) external;\n\n function submitQueuedShares(PoolId poolId, ShareClassId scId) external;\n\n function submitQueuedAssets(PoolId poolId, ShareClassId scId, AssetId assetId) external;\n\n function setQueue(PoolId poolId, ShareClassId scId, bool enabled) external;\n}\n" + }, + "src/common/interfaces/IGatewaySenders.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {D18} from \"src/misc/types/D18.sol\";\n\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\n\ninterface ILocalCentrifugeId {\n function localCentrifugeId() external view returns (uint16);\n}\n\n/// @notice Interface for dispatch-only gateway\ninterface IRootMessageSender {\n /// @notice Creates and send the message\n function sendScheduleUpgrade(uint16 centrifugeId, bytes32 target) external;\n\n /// @notice Creates and send the message\n function sendCancelUpgrade(uint16 centrifugeId, bytes32 target) external;\n\n /// @notice Creates and send the message\n function sendRecoverTokens(\n uint16 centrifugeId,\n bytes32 target,\n bytes32 token,\n uint256 tokenId,\n bytes32 to,\n uint256 amount\n ) external;\n\n /// @notice Creates and send the message\n function sendInitiateRecovery(uint16 centrifugeId, uint16 adapterCentrifugeId, bytes32 adapter, bytes32 hash)\n external;\n\n /// @notice Creates and send the message\n function sendDisputeRecovery(uint16 centrifugeId, uint16 adapterCentrifugeId, bytes32 adapter, bytes32 hash)\n external;\n}\n\n/// @notice Interface for dispatch-only gateway\ninterface IPoolMessageSender is ILocalCentrifugeId {\n /// @notice Creates and send the message\n function sendNotifyPool(uint16 centrifugeId, PoolId poolId) external;\n\n /// @notice Creates and send the message\n function sendNotifyShareClass(\n uint16 centrifugeId,\n PoolId poolId,\n ShareClassId scId,\n string memory name,\n string memory symbol,\n uint8 decimals,\n bytes32 salt,\n bytes32 hook\n ) external;\n\n /// @notice Creates and send the message\n function sendNotifyShareMetadata(\n uint16 centrifugeId,\n PoolId poolId,\n ShareClassId scId,\n string memory name,\n string memory symbol\n ) external;\n\n /// @notice Creates and send the message\n function sendUpdateShareHook(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bytes32 hook) external;\n\n /// @notice Creates and send the message\n function sendNotifyPricePoolPerShare(uint16 chainId, PoolId poolId, ShareClassId scId, D18 pricePerShare)\n external;\n\n /// @notice Creates and send the message\n function sendNotifyPricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId, D18 pricePerShare)\n external;\n\n /// @notice Creates and send the message\n function sendFulfilledDepositRequest(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n bytes32 investor,\n uint128 assetAmount,\n uint128 shareAmount\n ) external;\n\n /// @notice Creates and send the message\n function sendFulfilledRedeemRequest(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n bytes32 investor,\n uint128 assetAmount,\n uint128 shareAmount\n ) external;\n\n /// @notice Creates and send the message\n function sendFulfilledCancelDepositRequest(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n bytes32 investor,\n uint128 cancelledAmount\n ) external;\n\n /// @notice Creates and send the message\n function sendFulfilledCancelRedeemRequest(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n bytes32 investor,\n uint128 cancelledShares\n ) external;\n\n /// @notice Creates and send the message\n function sendUpdateRestriction(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bytes calldata payload)\n external;\n\n /// @notice Creates and send the message\n function sendUpdateContract(\n uint16 centrifugeId,\n PoolId poolId,\n ShareClassId scId,\n bytes32 target,\n bytes calldata payload\n ) external;\n\n /// @notice Creates and send the message\n function sendApprovedDeposits(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n uint128 assetAmount,\n D18 pricePoolPerAsset\n ) external;\n\n // @notice Creates and send the message\n function sendIssuedShares(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n uint128 shareAmount,\n D18 pricePoolPerShare\n ) external;\n\n /// @notice Creates and send the message\n function sendRevokedShares(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n uint128 assetAmount,\n uint128 shareAmount,\n D18 pricePoolPerShare\n ) external;\n\n /// @notice Creates and send the message\n function sendTriggerIssueShares(uint16 centrifugeId, PoolId poolId, ShareClassId scId, address who, uint128 shares)\n external;\n\n /// @notice Creates and send the message\n function sendTriggerSubmitQueuedShares(uint16 centrifugeId, PoolId poolId, ShareClassId scId) external;\n\n /// @notice Creates and send the message\n function sendTriggerSubmitQueuedAssets(PoolId poolId, ShareClassId scId, AssetId assetId) external;\n\n /// @notice Creates and send the message\n function sendSetQueue(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bool enabled) external;\n}\n\n/// @notice Interface for dispatch-only gateway\ninterface IVaultMessageSender is ILocalCentrifugeId {\n /// @notice Creates and send the message\n function sendTransferShares(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bytes32 receiver, uint128 amount)\n external;\n\n /// @notice Creates and send the message\n function sendDepositRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId assetId, uint128 amount)\n external;\n\n /// @notice Creates and send the message\n function sendRedeemRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId assetId, uint128 amount)\n external;\n\n /// @notice Creates and send the message\n function sendCancelDepositRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId assetId) external;\n\n /// @notice Creates and send the message\n function sendCancelRedeemRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId assetId) external;\n\n /// @notice Creates and send the message\n function sendRegisterAsset(uint16 centrifugeId, AssetId assetId, uint8 decimals) external;\n\n /// @notice Creates and send the message\n function sendUpdateHoldingAmount(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n address provider,\n uint128 amount,\n D18 pricePoolPerAsset,\n bool isIncrease\n ) external;\n\n /// @notice Creates and send the message\n function sendUpdateShares(PoolId poolId, ShareClassId scId, uint128 shares, bool isIssuance) external;\n}\n" + }, + "src/common/interfaces/IGuardian.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {IAdapter} from \"src/common/interfaces/IAdapter.sol\";\n\ninterface ISafe {\n function isOwner(address signer) external view returns (bool);\n}\n\ninterface IGuardian {\n error NotTheAuthorizedSafe();\n error NotTheAuthorizedSafeOrItsOwner();\n\n /// @notice Dispatched when the `what` parameter of `file()` is not supported by the implementation.\n error FileUnrecognizedParam();\n\n /// @notice Emitted when a call to `file()` was performed.\n event File(bytes32 indexed what, address addr);\n\n /// @notice Return the linked Safe\n function safe() external view returns (ISafe);\n\n /// @notice Updates a contract parameter.\n /// @param what Name of the parameter to update.\n /// Accepts a `bytes32` representation of 'sender' string value.\n /// @param data New value given to the `what` parameter\n function file(bytes32 what, address data) external;\n\n /// @notice Registers a new pool\n function createPool(PoolId poolId, address admin, AssetId currency) external;\n\n /// @notice Pause the protocol\n /// @dev callable by both safe and owners\n function pause() external;\n\n /// @notice Unpause the protocol\n /// @dev callable by safe only\n function unpause() external;\n\n /// @notice Schedule relying a target address on Root\n /// @dev callable by safe only\n function scheduleRely(address target) external;\n\n /// @notice Cancel a scheduled rely\n /// @dev callable by safe only\n function cancelRely(address target) external;\n\n /// @notice Schedule an upgrade (scheduled rely) on a specific chain\n /// @dev Only supports EVM targets today\n function scheduleUpgrade(uint16 centrifugeId, address target) external;\n\n /// @notice Cancel an upgrade (scheduled rely) on a specific chain\n /// @dev Only supports EVM targets today\n function cancelUpgrade(uint16 centrifugeId, address target) external;\n\n /// @notice Recover tokens on a specific chain\n /// @dev Only supports EVM targets today\n function recoverTokens(\n uint16 centrifugeId,\n address target,\n address token,\n uint256 tokenId,\n address to,\n uint256 amount\n ) external;\n\n /// @notice Initiate a gateway payload recovery on a specific chain\n /// @dev Only supports EVM targets today\n function initiateRecovery(uint16 centrifugeId, uint16 adapterCentrifugeId, IAdapter adapter, bytes32 hash)\n external;\n\n /// @notice Dispute a gateway paylaod recovery on a specific chain\n /// @dev Only supports EVM targets today\n function disputeRecovery(uint16 centrifugeId, uint16 adapterCentrifugeId, IAdapter adapter, bytes32 hash)\n external;\n}\n" + }, + "src/common/interfaces/IGuardianActions.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\n\ninterface IHubGuardianActions {\n /// @notice Creates a new pool. `msg.sender` will be the admin of the created pool.\n /// @param currency The pool currency. Usually an AssetId identifying by a ISO4217 code.\n function createPool(PoolId poolId, address admin, AssetId currency) external payable;\n}\n" + }, + "src/common/interfaces/IHook.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IERC165} from \"src/misc/interfaces/IERC7575.sol\";\n\nstruct HookData {\n bytes16 from;\n bytes16 to;\n}\n\nuint8 constant SUCCESS_CODE_ID = 0;\nstring constant SUCCESS_MESSAGE = \"transfer-allowed\";\n\nuint8 constant ERROR_CODE_ID = 1;\nstring constant ERROR_MESSAGE = \"transfer-blocked\";\n\n/// @dev Magic address denoting a transfer to the escrow\n/// @dev Solely used for gas saving since escrow is per pool\naddress constant ESCROW_HOOK_ID = address(uint160(uint8(0xce)));\n\n/// @notice Hook interface to customize share token behaviour\n/// @dev To detect specific system actions:\n/// Deposit request: address(0) -> address(user)\n/// Deposit claim: ESCROW_HOOK_ID -> address(user)\n/// Redeem request: address(user) -> ESCROW_HOOK_ID\n/// Redeem claim: address(user) -> address(0)\n/// Cross-chain transfer: address(user) -> address(uint160(chainId))\ninterface IHook is IERC165 {\n // --- Errors ---\n error TransferBlocked();\n error InvalidUpdate();\n\n /// @notice Callback on standard ERC20 transfer.\n /// @dev MUST return bytes4(keccak256(\"onERC20Transfer(address,address,uint256,(bytes16,bytes16))\"))\n /// if successful\n function onERC20Transfer(address from, address to, uint256 value, HookData calldata hookdata)\n external\n returns (bytes4);\n\n /// @notice Callback on authorized ERC20 transfer.\n /// @dev Cannot be blocked, can only be used to update state.\n /// Return value is ignored, only kept for compatibility with V2 share tokens.\n function onERC20AuthTransfer(address sender, address from, address to, uint256 value, HookData calldata hookdata)\n external\n returns (bytes4);\n\n /// @notice Check if given transfer can be performed\n function checkERC20Transfer(address from, address to, uint256 value, HookData calldata hookData)\n external\n view\n returns (bool);\n\n /// @notice Update a set of restriction for a token\n /// @dev MAY be user specific, which would be included in the encoded `update` value\n function updateRestriction(address token, bytes memory update) external;\n}\n" + }, + "src/common/interfaces/IMessageDispatcher.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IVaultMessageSender, IPoolMessageSender, IRootMessageSender} from \"src/common/interfaces/IGatewaySenders.sol\";\n\ninterface IMessageDispatcher is IRootMessageSender, IVaultMessageSender, IPoolMessageSender {\n /// @notice Emitted when a call to `file()` was performed.\n event File(bytes32 indexed what, address addr);\n\n /// @notice Dispatched when the `what` parameter of `file()` is not supported by the implementation.\n error FileUnrecognizedParam();\n\n /// @notice Updates a contract parameter.\n /// @param what Name of the parameter to update.\n /// Accepts a `bytes32` representation of 'hubRegistry' string value.\n /// @param data New value given to the `what` parameter\n function file(bytes32 what, address data) external;\n\n /// @notice Estimate sending a message through the gateway.\n /// If the message is to the same centrifugeId, then the estimation is 0.\n function estimate(uint16 centrifugeId, bytes calldata payload) external view returns (uint256 amount);\n}\n" + }, + "src/common/interfaces/IMessageHandler.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\n/// @notice Generic interface for entities that handle incoming messages\ninterface IMessageHandler {\n /// @notice Dispatched when an invalid message is trying to handle\n error InvalidMessage(uint8 code);\n\n /// @notice Handling incoming messages.\n /// @param centrifugeId Source chain\n /// @param message Incoming message\n function handle(uint16 centrifugeId, bytes calldata message) external;\n}\n" + }, + "src/common/interfaces/IMessageProcessor.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IMessageHandler} from \"src/common/interfaces/IMessageHandler.sol\";\nimport {IMessageProperties} from \"src/common/interfaces/IMessageProperties.sol\";\n\ninterface IMessageProcessor is IMessageHandler, IMessageProperties {\n /// @notice Emitted when a call to `file()` was performed.\n event File(bytes32 indexed what, address addr);\n\n /// @notice Dispatched when the `what` parameter of `file()` is not supported by the implementation.\n error FileUnrecognizedParam();\n\n /// @notice Updates a contract parameter.\n /// @param what Name of the parameter to update.\n /// Accepts a `bytes32` representation of 'hubRegistry' string value.\n /// @param data New value given to the `what` parameter\n function file(bytes32 what, address data) external;\n}\n" + }, + "src/common/interfaces/IMessageProperties.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\n\n/// @notice Defines methods to get properties from raw messages\ninterface IMessageProperties {\n /// @notice Inspect the message to tell if the message is recovery message\n function isMessageRecovery(bytes calldata message) external pure returns (bool);\n\n /// @notice Inspect the message to return the length\n function messageLength(bytes calldata message) external pure returns (uint16);\n\n /// @notice Inspect the message to return the associated PoolId if any\n function messagePoolId(bytes calldata message) external pure returns (PoolId);\n}\n" + }, + "src/common/interfaces/IMessageSender.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\n/// @notice Generic interface for entities that handles outgoing messages\ninterface IMessageSender {\n /// @notice Handling outgoing messages.\n /// @param centrifugeId Destination chain\n function send(uint16 centrifugeId, bytes calldata message) external;\n}\n" + }, + "src/common/interfaces/IRoot.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IMessageHandler} from \"src/common/interfaces/IMessageHandler.sol\";\n\ninterface IRoot {\n // --- Events ---\n event File(bytes32 indexed what, uint256 data);\n event Pause();\n event Unpause();\n event ScheduleRely(address indexed target, uint256 indexed scheduledTime);\n event CancelRely(address indexed target);\n event RelyContract(address indexed target, address indexed user);\n event DenyContract(address indexed target, address indexed user);\n event Endorse(address indexed user);\n event Veto(address indexed user);\n\n error DelayTooLong();\n error FileUnrecognizedParam();\n error TargetNotScheduled();\n error TargetNotReady();\n\n /// @notice Returns whether the root is paused\n function paused() external view returns (bool);\n\n /// @notice Returns the current timelock for adding new wards\n function delay() external view returns (uint256);\n\n /// @notice Trusted contracts within the system\n function endorsements(address target) external view returns (uint256);\n\n /// @notice Returns when `relyTarget` has passed the timelock\n function schedule(address relyTarget) external view returns (uint256 timestamp);\n\n // --- Administration ---\n /// @notice Updates a contract parameter\n /// @param what Accepts a bytes32 representation of 'delay'\n function file(bytes32 what, uint256 data) external;\n\n /// --- Endorsements ---\n /// @notice Endorses the `user`\n /// @dev Endorsed users are trusted contracts in the system. They are allowed to bypass\n /// token restrictions (e.g. the Escrow can automatically receive share class tokens by being endorsed), and\n /// can automatically set operators in ERC-7540 vaults (e.g. the VaultRouter) is always an operator.\n function endorse(address user) external;\n\n /// @notice Removes the endorsed user\n function veto(address user) external;\n\n /// @notice Returns whether the user is endorsed\n function endorsed(address user) external view returns (bool);\n\n // --- Pause management ---\n /// @notice Pause any contracts that depend on `Root.paused()`\n function pause() external;\n\n /// @notice Unpause any contracts that depend on `Root.paused()`\n function unpause() external;\n\n /// --- Timelocked ward management ---\n /// @notice Schedule relying a new ward after the delay has passed\n function scheduleRely(address target) external;\n\n /// @notice Cancel a pending scheduled rely\n function cancelRely(address target) external;\n\n /// @notice Execute a scheduled rely\n /// @dev Can be triggered by anyone since the scheduling is protected\n function executeScheduledRely(address target) external;\n\n /// --- External contract ward management ---\n /// @notice Make an address a ward on any contract that Root is a ward on\n function relyContract(address target, address user) external;\n\n /// @notice Removes an address as a ward on any contract that Root is a ward on\n function denyContract(address target, address user) external;\n}\n" + }, + "src/common/interfaces/ITokenRecoverer.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IRecoverable} from \"src/misc/interfaces/IRecoverable.sol\";\n\ninterface ITokenRecoverer {\n event RecoverTokens(\n IRecoverable indexed target, address indexed token, uint256 tokenId, address indexed to, uint256 amount\n );\n\n function recoverTokens(IRecoverable target, address token, uint256 tokenId, address to, uint256 amount) external;\n}\n" + }, + "src/common/interfaces/IWormholeAdapter.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IAdapter} from \"src/common/interfaces/IAdapter.sol\";\n\n// From https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/interfaces/IWormholeRelayer.sol#L75\ninterface IWormholeRelayer {\n /**\n * @notice Publishes an instruction for the default delivery provider\n * to relay a payload to the address `targetAddress` on chain `targetChain`\n * with gas limit `gasLimit` and `msg.value` equal to `receiverValue`\n *\n * Any refunds (from leftover gas) will be sent to `refundAddress` on chain `refundChain`\n * `targetAddress` must implement the IWormholeReceiver interface\n *\n * This function must be called with `msg.value` equal to `quoteEVMDeliveryPrice(targetChain, receiverValue,\n * gasLimit)`\n *\n * @param targetChain in Wormhole Chain ID format\n * @param targetAddress address to call on targetChain (that implements IWormholeReceiver)\n * @param payload arbitrary bytes to pass in as parameter in call to `targetAddress`\n * @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain\n * currency units)\n * @param gasLimit gas limit with which to call `targetAddress`. Any units of gas unused will be refunded according\n * to the\n * `targetChainRefundPerGasUnused` rate quoted by the delivery provider\n * @param refundChain The chain to deliver any refund to, in Wormhole Chain ID format\n * @param refundAddress The address on `refundChain` to deliver any refund to\n * @return sequence sequence number of published VAA containing delivery instructions\n */\n function sendPayloadToEvm(\n uint16 targetChain,\n address targetAddress,\n bytes memory payload,\n uint256 receiverValue,\n uint256 gasLimit,\n uint16 refundChain,\n address refundAddress\n ) external payable returns (uint64 sequence);\n\n /**\n * @notice Returns the price to request a relay to chain `targetChain`, using the default delivery provider\n *\n * @param targetChain in Wormhole Chain ID format\n * @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain\n * currency units)\n * @param gasLimit gas limit with which to call `targetAddress`.\n * @return nativePriceQuote Price, in units of current chain currency, that the delivery provider charges to perform\n * the relay\n * @return targetChainRefundPerGasUnused amount of target chain currency that will be refunded per unit of gas\n * unused,\n * if a refundAddress is specified.\n * Note: This value can be overridden by the delivery provider on the target chain. The returned value here\n * should be considered to be a\n * promise by the delivery provider of the amount of refund per gas unused that will be returned to the\n * refundAddress at the target chain.\n * If a delivery provider decides to override, this will be visible as part of the emitted Delivery event on\n * the target chain.\n */\n function quoteEVMDeliveryPrice(uint16 targetChain, uint256 receiverValue, uint256 gasLimit)\n external\n view\n returns (uint256 nativePriceQuote, uint256 targetChainRefundPerGasUnused);\n\n /**\n * @notice Returns the address of the current default delivery provider\n * @return deliveryProvider The address of (the default delivery provider)'s contract on this source\n * chain. This must be a contract that implements IDeliveryProvider.\n */\n function getDefaultDeliveryProvider() external view returns (address deliveryProvider);\n}\n\ninterface IWormholeDeliveryProvider {\n /// @notice Returns the chain ID.\n function chainId() external view returns (uint16);\n}\n\n// From\n// https://github.com/wormhole-foundation/wormhole/blob/main/relayer/ethereum/contracts/interfaces/relayer/IWormholeReceiver.sol\ninterface IWormholeReceiver {\n /**\n * @notice When a `send` is performed with this contract as the target, this function will be\n * invoked by the WormholeRelayer contract\n *\n * NOTE: This function should be restricted such that only the Wormhole Relayer contract can call it.\n *\n * We also recommend that this function checks that `sourceChain` and `sourceAddress` are indeed who\n * you expect to have requested the calling of `send` on the source chain\n *\n * The invocation of this function corresponding to the `send` request will have msg.value equal\n * to the receiverValue specified in the send request.\n *\n * If the invocation of this function reverts or exceeds the gas limit\n * specified by the send requester, this delivery will result in a `ReceiverFailure`.\n *\n * @param payload - an arbitrary message which was included in the delivery by the\n * requester. This message's signature will already have been verified (as long as msg.sender is the Wormhole\n * Relayer contract)\n * @param additionalMessages - Additional messages which were requested to be included in this delivery.\n * Note: There are no contract-level guarantees that the messages in this array are what was requested\n * so **you should verify any sensitive information given here!**\n *\n * For example, if a 'VaaKey' was specified on the source chain, then MAKE SURE the corresponding message here\n * has valid signatures (by calling `parseAndVerifyVM(message)` on the Wormhole core contract)\n *\n * This field can be used to perform and relay TokenBridge or CCTP transfers, and there are example\n * usages of this at\n * https://github.com/wormhole-foundation/hello-token\n * https://github.com/wormhole-foundation/hello-cctp\n *\n * @param sourceAddress - the (wormhole format) address on the sending chain which requested\n * this delivery.\n * @param sourceChain - the wormhole chain ID where this delivery was requested.\n * @param deliveryHash - the VAA hash of the deliveryVAA.\n *\n */\n function receiveWormholeMessages(\n bytes memory payload,\n bytes[] memory additionalMessages,\n bytes32 sourceAddress,\n uint16 sourceChain,\n bytes32 deliveryHash\n ) external payable;\n}\n\nstruct WormholeSource {\n uint16 centrifugeId;\n address addr;\n}\n\nstruct WormholeDestination {\n uint16 wormholeId;\n address addr;\n}\n\ninterface IWormholeAdapter is IAdapter, IWormholeReceiver {\n /// @dev see file() method\n event File(bytes32 indexed what, uint16 fromChainId, uint16 toChainId, address addr);\n\n error FileUnrecognizedParam();\n error NotWormholeRelayer();\n error InvalidSource();\n\n /// @dev Configures the adapter\n /// @param what Can be \"sources\" or \"destinations\".\n /// @param addr if what == \"sources\", it represents the source\n /// @param addr if what == \"destinations\", it represents the destination\n function file(bytes32 what, uint16 centrifugeId, uint16 wormholeId, address addr) external;\n}\n" + }, + "src/common/libraries/MessageLib.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\n\nenum MessageType {\n /// @dev Placeholder for null message type\n _Invalid,\n /// @dev Placeholder for proof message type\n _MessageProof,\n // -- Gateway messages\n InitiateRecovery,\n DisputeRecovery,\n // -- Root messages\n ScheduleUpgrade,\n CancelUpgrade,\n RecoverTokens,\n // -- Pool manager messages\n RegisterAsset,\n NotifyPool,\n NotifyShareClass,\n NotifyPricePoolPerShare,\n NotifyPricePoolPerAsset,\n NotifyShareMetadata,\n UpdateShareHook,\n TransferShares,\n UpdateRestriction,\n UpdateContract,\n ApprovedDeposits,\n IssuedShares,\n RevokedShares,\n // -- Investment manager messages\n DepositRequest,\n RedeemRequest,\n FulfilledDepositRequest,\n FulfilledRedeemRequest,\n CancelDepositRequest,\n CancelRedeemRequest,\n FulfilledCancelDepositRequest,\n FulfilledCancelRedeemRequest,\n // -- BalanceSheet messages\n UpdateHoldingAmount,\n UpdateShares,\n TriggerIssueShares,\n TriggerSubmitQueuedShares,\n TriggerSubmitQueuedAssets,\n SetQueue\n}\n\nenum UpdateRestrictionType {\n /// @dev Placeholder for null update restriction type\n Invalid,\n Member,\n Freeze,\n Unfreeze\n}\n\nenum UpdateContractType {\n /// @dev Placeholder for null update restriction type\n Invalid,\n VaultUpdate,\n UpdateManager,\n MaxAssetPriceAge,\n MaxSharePriceAge,\n Valuation,\n SyncDepositMaxReserve\n}\n\n/// @dev Used internally in the VaultUpdateMessage (not represent a submessage)\nenum VaultUpdateKind {\n DeployAndLink,\n Link,\n Unlink\n}\n\nlibrary MessageLib {\n using MessageLib for bytes;\n using BytesLib for bytes;\n using CastLib for *;\n\n error UnknownMessageType();\n\n /// @dev Encode all message lengths in this constant to avoid a large list of if/elseif checks\n /// and reduce generated bytecode.\n /// If the message has some dynamic part, will be added later in `messageLength()`.\n // forgefmt: disable-next-item\n uint256 constant MESSAGE_LENGTHS_1 =\n (67 << uint8(MessageType.InitiateRecovery) * 8) +\n (67 << uint8(MessageType.DisputeRecovery) * 8) +\n (33 << uint8(MessageType.ScheduleUpgrade) * 8) +\n (33 << uint8(MessageType.CancelUpgrade) * 8) +\n (161 << uint8(MessageType.RecoverTokens) * 8) +\n (18 << uint8(MessageType.RegisterAsset) * 8) +\n (9 << uint8(MessageType.NotifyPool) * 8) +\n (250 << uint8(MessageType.NotifyShareClass) * 8) +\n (49 << uint8(MessageType.NotifyPricePoolPerShare) * 8) +\n (65 << uint8(MessageType.NotifyPricePoolPerAsset) * 8) +\n (185 << uint8(MessageType.NotifyShareMetadata) * 8) +\n (57 << uint8(MessageType.UpdateShareHook) * 8) +\n (73 << uint8(MessageType.TransferShares) * 8) +\n (25 << uint8(MessageType.UpdateRestriction) * 8) +\n (57 << uint8(MessageType.UpdateContract) * 8) +\n (73 << uint8(MessageType.ApprovedDeposits) * 8) +\n (57 << uint8(MessageType.IssuedShares) * 8) +\n (89 << uint8(MessageType.RevokedShares) * 8) +\n (89 << uint8(MessageType.DepositRequest) * 8) +\n (89 << uint8(MessageType.RedeemRequest) * 8) +\n (105 << uint8(MessageType.FulfilledDepositRequest) * 8) +\n (105 << uint8(MessageType.FulfilledRedeemRequest) * 8) +\n (73 << uint8(MessageType.CancelDepositRequest) * 8) +\n (73 << uint8(MessageType.CancelRedeemRequest) * 8) +\n (89 << uint8(MessageType.FulfilledCancelDepositRequest) * 8) +\n (89 << uint8(MessageType.FulfilledCancelRedeemRequest) * 8) +\n (114 << uint8(MessageType.UpdateHoldingAmount) * 8) +\n (50 << uint8(MessageType.UpdateShares) * 8) +\n (73 << uint8(MessageType.TriggerIssueShares) * 8) +\n (25 << uint8(MessageType.TriggerSubmitQueuedShares) * 8);\n\n // forgefmt: disable-next-item\n uint256 constant MESSAGE_LENGTHS_2 =\n (41 << (uint8(MessageType.TriggerSubmitQueuedAssets) - 32) * 8) +\n (26 << (uint8(MessageType.SetQueue) - 32) * 8);\n\n function messageType(bytes memory message) internal pure returns (MessageType) {\n return MessageType(message.toUint8(0));\n }\n\n function messageCode(bytes memory message) internal pure returns (uint8) {\n return message.toUint8(0);\n }\n\n function messageLength(bytes memory message) internal pure returns (uint16 length) {\n uint8 kind = message.toUint8(0);\n require(kind <= uint8(type(MessageType).max), UnknownMessageType());\n\n length = (kind <= 31)\n ? uint16(uint8(bytes32(MESSAGE_LENGTHS_1)[31 - kind]))\n : uint16(uint8(bytes32(MESSAGE_LENGTHS_2)[63 - kind]));\n\n // Spetial treatment for messages with dynamic size:\n if (kind == uint8(MessageType.UpdateRestriction)) {\n length += 2 + message.toUint16(length); //payloadLength\n } else if (kind == uint8(MessageType.UpdateContract)) {\n length += 2 + message.toUint16(length); //payloadLength\n }\n }\n\n function messagePoolId(bytes memory message) internal pure returns (PoolId poolId) {\n uint8 kind = message.toUint8(0);\n\n // All messages from NotifyPool to SetQueue contains a PoolId in position 1.\n if (kind >= uint8(MessageType.NotifyPool) && kind <= uint8(MessageType.SetQueue)) {\n return PoolId.wrap(message.toUint64(1));\n } else {\n return PoolId.wrap(0);\n }\n }\n\n function updateRestrictionType(bytes memory message) internal pure returns (UpdateRestrictionType) {\n return UpdateRestrictionType(message.toUint8(0));\n }\n\n function updateContractType(bytes memory message) internal pure returns (UpdateContractType) {\n return UpdateContractType(message.toUint8(0));\n }\n\n //---------------------------------------\n // InitiateRecovery\n //---------------------------------------\n\n struct InitiateRecovery {\n bytes32 hash;\n bytes32 adapter;\n uint16 centrifugeId;\n }\n\n function deserializeInitiateRecovery(bytes memory data) internal pure returns (InitiateRecovery memory) {\n require(messageType(data) == MessageType.InitiateRecovery, UnknownMessageType());\n return InitiateRecovery({hash: data.toBytes32(1), adapter: data.toBytes32(33), centrifugeId: data.toUint16(65)});\n }\n\n function serialize(InitiateRecovery memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.InitiateRecovery, t.hash, t.adapter, t.centrifugeId);\n }\n\n //---------------------------------------\n // DisputeRecovery\n //---------------------------------------\n\n struct DisputeRecovery {\n bytes32 hash;\n bytes32 adapter;\n uint16 centrifugeId;\n }\n\n function deserializeDisputeRecovery(bytes memory data) internal pure returns (DisputeRecovery memory) {\n require(messageType(data) == MessageType.DisputeRecovery, UnknownMessageType());\n return DisputeRecovery({hash: data.toBytes32(1), adapter: data.toBytes32(33), centrifugeId: data.toUint16(65)});\n }\n\n function serialize(DisputeRecovery memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.DisputeRecovery, t.hash, t.adapter, t.centrifugeId);\n }\n\n //---------------------------------------\n // ScheduleUpgrade\n //---------------------------------------\n\n struct ScheduleUpgrade {\n bytes32 target;\n }\n\n function deserializeScheduleUpgrade(bytes memory data) internal pure returns (ScheduleUpgrade memory) {\n require(messageType(data) == MessageType.ScheduleUpgrade, UnknownMessageType());\n return ScheduleUpgrade({target: data.toBytes32(1)});\n }\n\n function serialize(ScheduleUpgrade memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.ScheduleUpgrade, t.target);\n }\n\n //---------------------------------------\n // CancelUpgrade\n //---------------------------------------\n\n struct CancelUpgrade {\n bytes32 target;\n }\n\n function deserializeCancelUpgrade(bytes memory data) internal pure returns (CancelUpgrade memory) {\n require(messageType(data) == MessageType.CancelUpgrade, UnknownMessageType());\n return CancelUpgrade({target: data.toBytes32(1)});\n }\n\n function serialize(CancelUpgrade memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.CancelUpgrade, t.target);\n }\n\n //---------------------------------------\n // RecoverTokens\n //---------------------------------------\n\n struct RecoverTokens {\n bytes32 target;\n bytes32 token;\n uint256 tokenId;\n bytes32 to;\n uint256 amount;\n }\n\n function deserializeRecoverTokens(bytes memory data) internal pure returns (RecoverTokens memory) {\n require(messageType(data) == MessageType.RecoverTokens, UnknownMessageType());\n return RecoverTokens({\n target: data.toBytes32(1),\n token: data.toBytes32(33),\n tokenId: data.toUint256(65),\n to: data.toBytes32(97),\n amount: data.toUint256(129)\n });\n }\n\n function serialize(RecoverTokens memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.RecoverTokens, t.target, t.token, t.tokenId, t.to, t.amount);\n }\n\n //---------------------------------------\n // RegisterAsset\n //---------------------------------------\n\n struct RegisterAsset {\n uint128 assetId;\n uint8 decimals;\n }\n\n function deserializeRegisterAsset(bytes memory data) internal pure returns (RegisterAsset memory) {\n require(messageType(data) == MessageType.RegisterAsset, UnknownMessageType());\n return RegisterAsset({assetId: data.toUint128(1), decimals: data.toUint8(17)});\n }\n\n function serialize(RegisterAsset memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.RegisterAsset, t.assetId, t.decimals);\n }\n\n //---------------------------------------\n // NotifyPool\n //---------------------------------------\n\n struct NotifyPool {\n uint64 poolId;\n }\n\n function deserializeNotifyPool(bytes memory data) internal pure returns (NotifyPool memory) {\n require(messageType(data) == MessageType.NotifyPool, UnknownMessageType());\n return NotifyPool({poolId: data.toUint64(1)});\n }\n\n function serialize(NotifyPool memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.NotifyPool, t.poolId);\n }\n\n //---------------------------------------\n // NotifyShareClass\n //---------------------------------------\n\n struct NotifyShareClass {\n uint64 poolId;\n bytes16 scId;\n string name; // Fixed to 128 bytes\n bytes32 symbol; // utf8\n uint8 decimals;\n bytes32 salt;\n bytes32 hook;\n }\n\n function deserializeNotifyShareClass(bytes memory data) internal pure returns (NotifyShareClass memory) {\n require(messageType(data) == MessageType.NotifyShareClass, UnknownMessageType());\n return NotifyShareClass({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n name: data.slice(25, 128).bytes128ToString(),\n symbol: data.toBytes32(153),\n decimals: data.toUint8(185),\n salt: data.toBytes32(186),\n hook: data.toBytes32(218)\n });\n }\n\n function serialize(NotifyShareClass memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(\n MessageType.NotifyShareClass,\n t.poolId,\n t.scId,\n bytes(t.name).sliceZeroPadded(0, 128),\n t.symbol,\n t.decimals,\n t.salt,\n t.hook\n );\n }\n\n //---------------------------------------\n // NotifyPricePoolPerShare\n //---------------------------------------\n\n struct NotifyPricePoolPerShare {\n uint64 poolId;\n bytes16 scId;\n uint128 price;\n uint64 timestamp;\n }\n\n function deserializeNotifyPricePoolPerShare(bytes memory data)\n internal\n pure\n returns (NotifyPricePoolPerShare memory)\n {\n require(messageType(data) == MessageType.NotifyPricePoolPerShare, UnknownMessageType());\n return NotifyPricePoolPerShare({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n price: data.toUint128(25),\n timestamp: data.toUint64(41)\n });\n }\n\n function serialize(NotifyPricePoolPerShare memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.NotifyPricePoolPerShare, t.poolId, t.scId, t.price, t.timestamp);\n }\n\n //---------------------------------------\n // NotifyPricePoolPerAsset\n //---------------------------------------\n\n struct NotifyPricePoolPerAsset {\n uint64 poolId;\n bytes16 scId;\n uint128 assetId;\n uint128 price;\n uint64 timestamp;\n }\n\n function deserializeNotifyPricePoolPerAsset(bytes memory data)\n internal\n pure\n returns (NotifyPricePoolPerAsset memory)\n {\n require(messageType(data) == MessageType.NotifyPricePoolPerAsset, UnknownMessageType());\n return NotifyPricePoolPerAsset({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n assetId: data.toUint128(25),\n price: data.toUint128(41),\n timestamp: data.toUint64(57)\n });\n }\n\n function serialize(NotifyPricePoolPerAsset memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.NotifyPricePoolPerAsset, t.poolId, t.scId, t.assetId, t.price, t.timestamp);\n }\n\n //---------------------------------------\n // NotifyShareMetadata\n //---------------------------------------\n\n struct NotifyShareMetadata {\n uint64 poolId;\n bytes16 scId;\n string name; // Fixed to 128 bytes\n bytes32 symbol; // utf8\n }\n\n function deserializeNotifyShareMetadata(bytes memory data) internal pure returns (NotifyShareMetadata memory) {\n require(messageType(data) == MessageType.NotifyShareMetadata, UnknownMessageType());\n return NotifyShareMetadata({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n name: data.slice(25, 128).bytes128ToString(),\n symbol: data.toBytes32(153)\n });\n }\n\n function serialize(NotifyShareMetadata memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(\n MessageType.NotifyShareMetadata, t.poolId, t.scId, bytes(t.name).sliceZeroPadded(0, 128), t.symbol\n );\n }\n\n //---------------------------------------\n // UpdateShareHook\n //---------------------------------------\n\n struct UpdateShareHook {\n uint64 poolId;\n bytes16 scId;\n bytes32 hook;\n }\n\n function deserializeUpdateShareHook(bytes memory data) internal pure returns (UpdateShareHook memory) {\n require(messageType(data) == MessageType.UpdateShareHook, UnknownMessageType());\n return UpdateShareHook({poolId: data.toUint64(1), scId: data.toBytes16(9), hook: data.toBytes32(25)});\n }\n\n function serialize(UpdateShareHook memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.UpdateShareHook, t.poolId, t.scId, t.hook);\n }\n\n //---------------------------------------\n // TransferShares\n //---------------------------------------\n\n struct TransferShares {\n uint64 poolId;\n bytes16 scId;\n bytes32 receiver;\n uint128 amount;\n }\n\n function deserializeTransferShares(bytes memory data) internal pure returns (TransferShares memory) {\n require(messageType(data) == MessageType.TransferShares, UnknownMessageType());\n return TransferShares({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n receiver: data.toBytes32(25),\n amount: data.toUint128(57)\n });\n }\n\n function serialize(TransferShares memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.TransferShares, t.poolId, t.scId, t.receiver, t.amount);\n }\n\n //---------------------------------------\n // UpdateRestriction\n //---------------------------------------\n\n struct UpdateRestriction {\n uint64 poolId;\n bytes16 scId;\n bytes payload; // As sequence of bytes\n }\n\n function deserializeUpdateRestriction(bytes memory data) internal pure returns (UpdateRestriction memory) {\n require(messageType(data) == MessageType.UpdateRestriction, UnknownMessageType());\n\n uint16 payloadLength = data.toUint16(25);\n return UpdateRestriction({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n payload: data.slice(27, payloadLength)\n });\n }\n\n function serialize(UpdateRestriction memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.UpdateRestriction, t.poolId, t.scId, uint16(t.payload.length), t.payload);\n }\n\n //---------------------------------------\n // UpdateRestrictionMember (submsg)\n //---------------------------------------\n\n struct UpdateRestrictionMember {\n bytes32 user;\n uint64 validUntil;\n }\n\n function deserializeUpdateRestrictionMember(bytes memory data)\n internal\n pure\n returns (UpdateRestrictionMember memory)\n {\n require(updateRestrictionType(data) == UpdateRestrictionType.Member, UnknownMessageType());\n\n return UpdateRestrictionMember({user: data.toBytes32(1), validUntil: data.toUint64(33)});\n }\n\n function serialize(UpdateRestrictionMember memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(UpdateRestrictionType.Member, t.user, t.validUntil);\n }\n\n //---------------------------------------\n // UpdateRestrictionFreeze (submsg)\n //---------------------------------------\n\n struct UpdateRestrictionFreeze {\n bytes32 user;\n }\n\n function deserializeUpdateRestrictionFreeze(bytes memory data)\n internal\n pure\n returns (UpdateRestrictionFreeze memory)\n {\n require(updateRestrictionType(data) == UpdateRestrictionType.Freeze, UnknownMessageType());\n\n return UpdateRestrictionFreeze({user: data.toBytes32(1)});\n }\n\n function serialize(UpdateRestrictionFreeze memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(UpdateRestrictionType.Freeze, t.user);\n }\n\n //---------------------------------------\n // UpdateRestrictionUnfreeze (submsg)\n //---------------------------------------\n\n struct UpdateRestrictionUnfreeze {\n bytes32 user;\n }\n\n function deserializeUpdateRestrictionUnfreeze(bytes memory data)\n internal\n pure\n returns (UpdateRestrictionUnfreeze memory)\n {\n require(updateRestrictionType(data) == UpdateRestrictionType.Unfreeze, UnknownMessageType());\n\n return UpdateRestrictionUnfreeze({user: data.toBytes32(1)});\n }\n\n function serialize(UpdateRestrictionUnfreeze memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(UpdateRestrictionType.Unfreeze, t.user);\n }\n\n //---------------------------------------\n // UpdateContract\n //---------------------------------------\n\n struct UpdateContract {\n uint64 poolId;\n bytes16 scId;\n bytes32 target;\n bytes payload; // As sequence of bytes\n }\n\n function deserializeUpdateContract(bytes memory data) internal pure returns (UpdateContract memory) {\n require(messageType(data) == MessageType.UpdateContract, UnknownMessageType());\n uint16 payloadLength = data.toUint16(57);\n return UpdateContract({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n target: data.toBytes32(25),\n payload: data.slice(59, payloadLength)\n });\n }\n\n function serialize(UpdateContract memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(\n MessageType.UpdateContract, t.poolId, t.scId, t.target, uint16(t.payload.length), t.payload\n );\n }\n\n //---------------------------------------\n // UpdateContract.VaultUpdate (submsg)\n //---------------------------------------\n\n struct UpdateContractVaultUpdate {\n bytes32 vaultOrFactory;\n uint128 assetId;\n uint8 kind;\n }\n\n function deserializeUpdateContractVaultUpdate(bytes memory data)\n internal\n pure\n returns (UpdateContractVaultUpdate memory)\n {\n require(updateContractType(data) == UpdateContractType.VaultUpdate, UnknownMessageType());\n\n return UpdateContractVaultUpdate({\n vaultOrFactory: data.toBytes32(1),\n assetId: data.toUint128(33),\n kind: data.toUint8(49)\n });\n }\n\n function serialize(UpdateContractVaultUpdate memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(UpdateContractType.VaultUpdate, t.vaultOrFactory, t.assetId, t.kind);\n }\n\n //---------------------------------------\n // UpdateContract.UpdateManager (submsg)\n //---------------------------------------\n\n struct UpdateContractUpdateManager {\n bytes32 who;\n bool canManage;\n }\n\n function deserializeUpdateContractUpdateManager(bytes memory data)\n internal\n pure\n returns (UpdateContractUpdateManager memory)\n {\n require(updateContractType(data) == UpdateContractType.UpdateManager, UnknownMessageType());\n\n return UpdateContractUpdateManager({who: data.toBytes32(1), canManage: data.toBool(33)});\n }\n\n function serialize(UpdateContractUpdateManager memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(UpdateContractType.UpdateManager, t.who, t.canManage);\n }\n\n //---------------------------------------\n // UpdateContract.MaxAssetPriceAge (submsg)\n //---------------------------------------\n\n struct UpdateContractMaxAssetPriceAge {\n uint128 assetId;\n uint64 maxPriceAge;\n }\n\n function deserializeUpdateContractMaxAssetPriceAge(bytes memory data)\n internal\n pure\n returns (UpdateContractMaxAssetPriceAge memory)\n {\n require(updateContractType(data) == UpdateContractType.MaxAssetPriceAge, UnknownMessageType());\n\n return UpdateContractMaxAssetPriceAge({assetId: data.toUint128(1), maxPriceAge: data.toUint64(17)});\n }\n\n function serialize(UpdateContractMaxAssetPriceAge memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(UpdateContractType.MaxAssetPriceAge, t.assetId, t.maxPriceAge);\n }\n\n //---------------------------------------\n // UpdateContract.MaxSharePriceAge (submsg)\n //---------------------------------------\n\n struct UpdateContractMaxSharePriceAge {\n uint64 maxPriceAge;\n }\n\n function deserializeUpdateContractMaxSharePriceAge(bytes memory data)\n internal\n pure\n returns (UpdateContractMaxSharePriceAge memory)\n {\n require(updateContractType(data) == UpdateContractType.MaxSharePriceAge, UnknownMessageType());\n\n return UpdateContractMaxSharePriceAge({maxPriceAge: data.toUint64(1)});\n }\n\n function serialize(UpdateContractMaxSharePriceAge memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(UpdateContractType.MaxSharePriceAge, t.maxPriceAge);\n }\n\n //---------------------------------------\n // UpdateContract.Valuation (submsg)\n //---------------------------------------\n\n struct UpdateContractValuation {\n bytes32 valuation;\n }\n\n function deserializeUpdateContractValuation(bytes memory data)\n internal\n pure\n returns (UpdateContractValuation memory)\n {\n require(updateContractType(data) == UpdateContractType.Valuation, UnknownMessageType());\n\n return UpdateContractValuation({valuation: data.toBytes32(1)});\n }\n\n function serialize(UpdateContractValuation memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(UpdateContractType.Valuation, t.valuation);\n }\n\n //---------------------------------------\n // UpdateContract.SyncDepositMaxReserve (submsg)\n //---------------------------------------\n\n struct UpdateContractSyncDepositMaxReserve {\n uint128 assetId;\n uint128 maxReserve;\n }\n\n function deserializeUpdateContractSyncDepositMaxReserve(bytes memory data)\n internal\n pure\n returns (UpdateContractSyncDepositMaxReserve memory)\n {\n require(updateContractType(data) == UpdateContractType.SyncDepositMaxReserve, UnknownMessageType());\n\n return UpdateContractSyncDepositMaxReserve({assetId: data.toUint128(1), maxReserve: data.toUint128(17)});\n }\n\n function serialize(UpdateContractSyncDepositMaxReserve memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(UpdateContractType.SyncDepositMaxReserve, t.assetId, t.maxReserve);\n }\n\n //---------------------------------------\n // DepositRequest\n //---------------------------------------\n\n struct DepositRequest {\n uint64 poolId;\n bytes16 scId;\n bytes32 investor;\n uint128 assetId;\n uint128 amount;\n }\n\n function deserializeDepositRequest(bytes memory data) internal pure returns (DepositRequest memory) {\n require(messageType(data) == MessageType.DepositRequest, UnknownMessageType());\n return DepositRequest({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n investor: data.toBytes32(25),\n assetId: data.toUint128(57),\n amount: data.toUint128(73)\n });\n }\n\n function serialize(DepositRequest memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.DepositRequest, t.poolId, t.scId, t.investor, t.assetId, t.amount);\n }\n\n //---------------------------------------\n // RedeemRequest\n //---------------------------------------\n\n struct RedeemRequest {\n uint64 poolId;\n bytes16 scId;\n bytes32 investor;\n uint128 assetId;\n uint128 amount;\n }\n\n function deserializeRedeemRequest(bytes memory data) internal pure returns (RedeemRequest memory) {\n require(messageType(data) == MessageType.RedeemRequest, UnknownMessageType());\n return RedeemRequest({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n investor: data.toBytes32(25),\n assetId: data.toUint128(57),\n amount: data.toUint128(73)\n });\n }\n\n function serialize(RedeemRequest memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.RedeemRequest, t.poolId, t.scId, t.investor, t.assetId, t.amount);\n }\n\n //---------------------------------------\n // CancelDepositRequest\n //---------------------------------------\n\n struct CancelDepositRequest {\n uint64 poolId;\n bytes16 scId;\n bytes32 investor;\n uint128 assetId;\n }\n\n function deserializeCancelDepositRequest(bytes memory data) internal pure returns (CancelDepositRequest memory) {\n require(messageType(data) == MessageType.CancelDepositRequest, UnknownMessageType());\n return CancelDepositRequest({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n investor: data.toBytes32(25),\n assetId: data.toUint128(57)\n });\n }\n\n function serialize(CancelDepositRequest memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.CancelDepositRequest, t.poolId, t.scId, t.investor, t.assetId);\n }\n\n //---------------------------------------\n // CancelRedeemRequest\n //---------------------------------------\n\n struct CancelRedeemRequest {\n uint64 poolId;\n bytes16 scId;\n bytes32 investor;\n uint128 assetId;\n }\n\n function deserializeCancelRedeemRequest(bytes memory data) internal pure returns (CancelRedeemRequest memory) {\n require(messageType(data) == MessageType.CancelRedeemRequest, UnknownMessageType());\n return CancelRedeemRequest({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n investor: data.toBytes32(25),\n assetId: data.toUint128(57)\n });\n }\n\n function serialize(CancelRedeemRequest memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.CancelRedeemRequest, t.poolId, t.scId, t.investor, t.assetId);\n }\n\n //---------------------------------------\n // FulfilledDepositRequest\n //---------------------------------------\n\n struct FulfilledDepositRequest {\n uint64 poolId;\n bytes16 scId;\n bytes32 investor;\n uint128 assetId;\n uint128 assetAmount;\n uint128 shareAmount;\n }\n\n function deserializeFulfilledDepositRequest(bytes memory data)\n internal\n pure\n returns (FulfilledDepositRequest memory)\n {\n require(messageType(data) == MessageType.FulfilledDepositRequest, UnknownMessageType());\n return FulfilledDepositRequest({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n investor: data.toBytes32(25),\n assetId: data.toUint128(57),\n assetAmount: data.toUint128(73),\n shareAmount: data.toUint128(89)\n });\n }\n\n function serialize(FulfilledDepositRequest memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(\n MessageType.FulfilledDepositRequest, t.poolId, t.scId, t.investor, t.assetId, t.assetAmount, t.shareAmount\n );\n }\n\n //---------------------------------------\n // FulfilledRedeemRequest\n //---------------------------------------\n\n struct FulfilledRedeemRequest {\n uint64 poolId;\n bytes16 scId;\n bytes32 investor;\n uint128 assetId;\n uint128 assetAmount;\n uint128 shareAmount;\n }\n\n function deserializeFulfilledRedeemRequest(bytes memory data)\n internal\n pure\n returns (FulfilledRedeemRequest memory)\n {\n require(messageType(data) == MessageType.FulfilledRedeemRequest, UnknownMessageType());\n return FulfilledRedeemRequest({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n investor: data.toBytes32(25),\n assetId: data.toUint128(57),\n assetAmount: data.toUint128(73),\n shareAmount: data.toUint128(89)\n });\n }\n\n function serialize(FulfilledRedeemRequest memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(\n MessageType.FulfilledRedeemRequest, t.poolId, t.scId, t.investor, t.assetId, t.assetAmount, t.shareAmount\n );\n }\n\n //---------------------------------------\n // FulfilledCancelDepositRequest\n //---------------------------------------\n\n struct FulfilledCancelDepositRequest {\n uint64 poolId;\n bytes16 scId;\n bytes32 investor;\n uint128 assetId;\n uint128 cancelledAmount;\n }\n\n function deserializeFulfilledCancelDepositRequest(bytes memory data)\n internal\n pure\n returns (FulfilledCancelDepositRequest memory)\n {\n require(messageType(data) == MessageType.FulfilledCancelDepositRequest, UnknownMessageType());\n return FulfilledCancelDepositRequest({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n investor: data.toBytes32(25),\n assetId: data.toUint128(57),\n cancelledAmount: data.toUint128(73)\n });\n }\n\n function serialize(FulfilledCancelDepositRequest memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(\n MessageType.FulfilledCancelDepositRequest, t.poolId, t.scId, t.investor, t.assetId, t.cancelledAmount\n );\n }\n\n //---------------------------------------\n // FulfilledCancelRedeemRequest\n //---------------------------------------\n\n struct FulfilledCancelRedeemRequest {\n uint64 poolId;\n bytes16 scId;\n bytes32 investor;\n uint128 assetId;\n uint128 cancelledShares;\n }\n\n function deserializeFulfilledCancelRedeemRequest(bytes memory data)\n internal\n pure\n returns (FulfilledCancelRedeemRequest memory)\n {\n require(messageType(data) == MessageType.FulfilledCancelRedeemRequest, UnknownMessageType());\n return FulfilledCancelRedeemRequest({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n investor: data.toBytes32(25),\n assetId: data.toUint128(57),\n cancelledShares: data.toUint128(73)\n });\n }\n\n function serialize(FulfilledCancelRedeemRequest memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(\n MessageType.FulfilledCancelRedeemRequest, t.poolId, t.scId, t.investor, t.assetId, t.cancelledShares\n );\n }\n\n //---------------------------------------\n // UpdateHoldingAmount\n //---------------------------------------\n\n struct UpdateHoldingAmount {\n uint64 poolId;\n bytes16 scId;\n uint128 assetId;\n bytes32 who;\n uint128 amount;\n uint128 pricePerUnit;\n uint64 timestamp;\n bool isIncrease; // Signals whether this is an increase or a decrease\n }\n\n function deserializeUpdateHoldingAmount(bytes memory data) internal pure returns (UpdateHoldingAmount memory h) {\n require(messageType(data) == MessageType.UpdateHoldingAmount, \"UnknownMessageType\");\n\n return UpdateHoldingAmount({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n assetId: data.toUint128(25),\n who: data.toBytes32(41),\n amount: data.toUint128(73),\n pricePerUnit: data.toUint128(89),\n timestamp: data.toUint64(105),\n isIncrease: data.toBool(113)\n });\n }\n\n function serialize(UpdateHoldingAmount memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(\n MessageType.UpdateHoldingAmount,\n t.poolId,\n t.scId,\n t.assetId,\n t.who,\n t.amount,\n t.pricePerUnit,\n t.timestamp,\n t.isIncrease\n );\n }\n\n //---------------------------------------\n // UpdateShares\n //---------------------------------------\n\n struct UpdateShares {\n uint64 poolId;\n bytes16 scId;\n uint128 shares;\n uint64 timestamp;\n bool isIssuance;\n }\n\n function deserializeUpdateShares(bytes memory data) internal pure returns (UpdateShares memory) {\n require(messageType(data) == MessageType.UpdateShares, UnknownMessageType());\n\n return UpdateShares({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n shares: data.toUint128(25),\n timestamp: data.toUint64(41),\n isIssuance: data.toBool(49)\n });\n }\n\n function serialize(UpdateShares memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.UpdateShares, t.poolId, t.scId, t.shares, t.timestamp, t.isIssuance);\n }\n\n //---------------------------------------\n // ApprovedDeposits\n //---------------------------------------\n\n struct ApprovedDeposits {\n uint64 poolId;\n bytes16 scId;\n uint128 assetId;\n uint128 assetAmount;\n uint128 pricePoolPerAsset;\n }\n\n function deserializeApprovedDeposits(bytes memory data) internal pure returns (ApprovedDeposits memory) {\n require(messageType(data) == MessageType.ApprovedDeposits, UnknownMessageType());\n\n return ApprovedDeposits({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n assetId: data.toUint128(25),\n assetAmount: data.toUint128(41),\n pricePoolPerAsset: data.toUint128(57)\n });\n }\n\n function serialize(ApprovedDeposits memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(\n MessageType.ApprovedDeposits, t.poolId, t.scId, t.assetId, t.assetAmount, t.pricePoolPerAsset\n );\n }\n\n //---------------------------------------\n // IssuedShares\n //---------------------------------------\n\n struct IssuedShares {\n uint64 poolId;\n bytes16 scId;\n uint128 shareAmount;\n uint128 pricePoolPerShare;\n }\n\n function deserializeIssuedShares(bytes memory data) internal pure returns (IssuedShares memory) {\n require(messageType(data) == MessageType.IssuedShares, UnknownMessageType());\n\n return IssuedShares({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n shareAmount: data.toUint128(25),\n pricePoolPerShare: data.toUint128(41)\n });\n }\n\n function serialize(IssuedShares memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.IssuedShares, t.poolId, t.scId, t.shareAmount, t.pricePoolPerShare);\n }\n\n //---------------------------------------\n // RevokedShares\n //---------------------------------------\n\n struct RevokedShares {\n uint64 poolId;\n bytes16 scId;\n uint128 assetId;\n uint128 shareAmount;\n uint128 pricePoolPerShare;\n uint128 assetAmount;\n }\n\n function deserializeRevokedShares(bytes memory data) internal pure returns (RevokedShares memory) {\n require(messageType(data) == MessageType.RevokedShares, UnknownMessageType());\n\n return RevokedShares({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n assetId: data.toUint128(25),\n assetAmount: data.toUint128(41),\n shareAmount: data.toUint128(57),\n pricePoolPerShare: data.toUint128(73)\n });\n }\n\n function serialize(RevokedShares memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(\n MessageType.RevokedShares, t.poolId, t.scId, t.assetId, t.assetAmount, t.shareAmount, t.pricePoolPerShare\n );\n }\n\n //---------------------------------------\n // TriggerIssueShares\n //---------------------------------------\n\n struct TriggerIssueShares {\n uint64 poolId;\n bytes16 scId;\n bytes32 who;\n uint128 shares;\n }\n\n function deserializeTriggerIssueShares(bytes memory data) internal pure returns (TriggerIssueShares memory) {\n require(messageType(data) == MessageType.TriggerIssueShares, UnknownMessageType());\n\n return TriggerIssueShares({\n poolId: data.toUint64(1),\n scId: data.toBytes16(9),\n who: data.toBytes32(25),\n shares: data.toUint128(57)\n });\n }\n\n function serialize(TriggerIssueShares memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.TriggerIssueShares, t.poolId, t.scId, t.who, t.shares);\n }\n\n //---------------------------------------\n // TriggerSubmitQueuedShares\n //---------------------------------------\n\n struct TriggerSubmitQueuedShares {\n uint64 poolId;\n bytes16 scId;\n }\n\n function deserializeTriggerSubmitQueuedShares(bytes memory data)\n internal\n pure\n returns (TriggerSubmitQueuedShares memory)\n {\n require(messageType(data) == MessageType.TriggerSubmitQueuedShares, UnknownMessageType());\n return TriggerSubmitQueuedShares({poolId: data.toUint64(1), scId: data.toBytes16(9)});\n }\n\n function serialize(TriggerSubmitQueuedShares memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.TriggerSubmitQueuedShares, t.poolId, t.scId);\n }\n\n //---------------------------------------\n // TriggerSubmitQueuedAssets\n //---------------------------------------\n\n struct TriggerSubmitQueuedAssets {\n uint64 poolId;\n bytes16 scId;\n uint128 assetId;\n }\n\n function deserializeTriggerSubmitQueuedAssets(bytes memory data)\n internal\n pure\n returns (TriggerSubmitQueuedAssets memory)\n {\n require(messageType(data) == MessageType.TriggerSubmitQueuedAssets, UnknownMessageType());\n return\n TriggerSubmitQueuedAssets({poolId: data.toUint64(1), scId: data.toBytes16(9), assetId: data.toUint128(25)});\n }\n\n function serialize(TriggerSubmitQueuedAssets memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.TriggerSubmitQueuedAssets, t.poolId, t.scId, t.assetId);\n }\n\n //---------------------------------------\n // SetQueue\n //---------------------------------------\n\n struct SetQueue {\n uint64 poolId;\n bytes16 scId;\n bool enabled;\n }\n\n function deserializeSetQueue(bytes memory data) internal pure returns (SetQueue memory) {\n require(messageType(data) == MessageType.SetQueue, UnknownMessageType());\n return SetQueue({poolId: data.toUint64(1), scId: data.toBytes16(9), enabled: data.toBool(25)});\n }\n\n function serialize(SetQueue memory t) internal pure returns (bytes memory) {\n return abi.encodePacked(MessageType.SetQueue, t.poolId, t.scId, t.enabled);\n }\n}\n" + }, + "src/common/libraries/MessageProofLib.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\n\nlibrary MessageProofLib {\n using BytesLib for bytes;\n\n uint8 constant MESSAGE_PROOF_ID = 1;\n\n error UnknownMessageProofType();\n\n function deserializeMessageProof(bytes memory data) internal pure returns (bytes32) {\n require(data.toUint8(0) == MESSAGE_PROOF_ID, UnknownMessageProofType());\n return data.toBytes32(1);\n }\n\n function serializeMessageProof(bytes32 hash) internal pure returns (bytes memory) {\n return abi.encodePacked(MESSAGE_PROOF_ID, hash);\n }\n}\n" + }, + "src/common/libraries/PricingLib.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {IERC20Metadata} from \"src/misc/interfaces/IERC20.sol\";\nimport {IERC6909MetadataExt} from \"src/misc/interfaces/IERC6909.sol\";\nimport {D18, d18} from \"src/misc/types/D18.sol\";\n\nimport {PricingLib} from \"src/common/libraries/PricingLib.sol\";\n\nlibrary PricingLib {\n using MathLib for *;\n\n /// @dev Prices are fixed-point integers with 18 decimals\n uint8 internal constant PRICE_DECIMALS = 18;\n\n /// -----------------------------------------------------\n /// View Methods\n /// -----------------------------------------------------\n\n /// @dev Converts the given asset amount to share amount. Returned value is in share decimals.\n ///\n /// @dev NOTE: MUST ONLY be used in AsyncRequestManager which rely on priceAssetPerShare that is derived from\n /// Fulfilled*\n /// message amounts. Any other codepath must use the variant with pricePoolPerAsset and pricePoolPerShare\n function assetToShareAmount(\n address shareToken,\n address asset,\n uint256 tokenId,\n uint128 assetAmount,\n D18 priceAssetPerShare_,\n MathLib.Rounding rounding\n ) internal view returns (uint128 shares) {\n if (assetAmount == 0 || priceAssetPerShare_.raw() == 0) {\n return 0;\n }\n\n uint8 assetDecimals = getAssetDecimals(asset, tokenId);\n uint8 shareDecimals = IERC20Metadata(shareToken).decimals();\n\n return PricingLib.convertWithReciprocalPrice(\n assetAmount, assetDecimals, shareDecimals, priceAssetPerShare_, rounding\n ).toUint128();\n }\n\n /// @dev Converts the given asset amount to share amount. Returned value is in share decimals.\n function assetToShareAmount(\n address shareToken,\n address asset,\n uint256 tokenId,\n uint128 assetAmount,\n D18 pricePoolPerAsset,\n D18 pricePoolPerShare,\n MathLib.Rounding rounding\n ) internal view returns (uint128 shares) {\n if (assetAmount == 0 || pricePoolPerShare.raw() == 0 || pricePoolPerAsset.raw() == 0) {\n return 0;\n }\n\n uint8 assetDecimals = getAssetDecimals(asset, tokenId);\n uint8 shareDecimals = IERC20Metadata(shareToken).decimals();\n\n return PricingLib.assetToShareAmount(\n assetAmount, assetDecimals, shareDecimals, pricePoolPerAsset, pricePoolPerShare, rounding\n ).toUint128();\n }\n\n /// @dev Converts the given share amount to asset amount. Returned value is in share decimals.\n ///\n /// @dev NOTE: MUST ONLY be used in AsyncRequestManager which rely on priceAssetPerShare that is derived from\n /// Fulfilled*\n /// message amounts. Any other codepath must use the variant with pricePoolPerAsset and pricePoolPerShare\n function shareToAssetAmount(\n address shareToken,\n uint128 shareAmount,\n address asset,\n uint256 tokenId,\n D18 priceAssetPerShare_,\n MathLib.Rounding rounding\n ) internal view returns (uint128 shares) {\n if (shareAmount == 0 || priceAssetPerShare_.raw() == 0) {\n return 0;\n }\n\n uint8 assetDecimals = getAssetDecimals(asset, tokenId);\n uint8 shareDecimals = IERC20Metadata(shareToken).decimals();\n\n return PricingLib.convertWithPrice(shareAmount, shareDecimals, assetDecimals, priceAssetPerShare_, rounding)\n .toUint128();\n }\n\n /// @dev Converts the given share amount to asset amount. Returned value is in share decimals.\n function shareToAssetAmount(\n address shareToken,\n uint128 shareAmount,\n address asset,\n uint256 tokenId,\n D18 pricePoolPerAsset,\n D18 pricePoolPerShare,\n MathLib.Rounding rounding\n ) internal view returns (uint128 shares) {\n if (shareAmount == 0 || pricePoolPerShare.raw() == 0 || pricePoolPerAsset.raw() == 0) {\n return 0;\n }\n\n uint8 assetDecimals = getAssetDecimals(asset, tokenId);\n uint8 shareDecimals = IERC20Metadata(shareToken).decimals();\n\n return PricingLib.shareToAssetAmount(\n shareAmount, shareDecimals, assetDecimals, pricePoolPerAsset, pricePoolPerShare, rounding\n ).toUint128();\n }\n\n /// @dev Calculates the asset price per share returns the value in price decimals\n /// Denominated in ASSET_UNIT/SHARE_UNIT\n function calculatePriceAssetPerShare(\n address shareToken,\n uint128 shares,\n address asset,\n uint256 tokenId,\n uint128 assets,\n MathLib.Rounding rounding\n ) internal view returns (uint256 priceAssetPerShare_) {\n if (assets == 0 || shares == 0) {\n return 0;\n }\n\n uint8 assetDecimals = getAssetDecimals(asset, tokenId);\n uint8 shareDecimals = IERC20Metadata(shareToken).decimals();\n\n // NOTE: More precise than d18(assets * 10 ** assetDecimals, shares * 10 ** shareDecimals)\n return toPriceDecimals(assets, assetDecimals).mulDiv(\n 10 ** PRICE_DECIMALS, toPriceDecimals(shares, shareDecimals), rounding\n );\n }\n\n /// -----------------------------------------------------\n /// Pure Methods\n /// -----------------------------------------------------\n\n /// @dev Converts an amount using decimals and price with implicit rounding down\n function convertWithPrice(uint256 baseAmount, uint8 baseDecimals, uint8 quoteDecimals, D18 priceQuotePerBase)\n internal\n pure\n returns (uint256 quoteAmount)\n {\n return convertWithPrice(baseAmount, baseDecimals, quoteDecimals, priceQuotePerBase, MathLib.Rounding.Down);\n }\n\n /// @dev Converts an amount using decimals and price with explicit rounding.\n function convertWithPrice(\n uint256 baseAmount,\n uint8 baseDecimals,\n uint8 quoteDecimals,\n D18 priceQuotePerBase,\n MathLib.Rounding rounding\n ) internal pure returns (uint256 quoteAmount) {\n if (baseDecimals == quoteDecimals) {\n return priceQuotePerBase.mulUint256(baseAmount, rounding);\n }\n\n return\n priceQuotePerBase.mulUint256(MathLib.mulDiv(baseAmount, 10 ** quoteDecimals, 10 ** baseDecimals), rounding);\n }\n\n /// @dev Converts an amount using decimals and reciprocal price.\n ///\n /// NOTE: More precise than convertWithPrice(,,,price.reciprocal,)\n function convertWithReciprocalPrice(\n uint256 baseAmount,\n uint8 baseDecimals,\n uint8 quoteDecimals,\n D18 priceBasePerQuote,\n MathLib.Rounding rounding\n ) internal pure returns (uint256 quoteAmount) {\n if (baseDecimals == quoteDecimals) {\n return priceBasePerQuote.reciprocalMulUint256(baseAmount, rounding);\n }\n\n return priceBasePerQuote.reciprocalMulUint256(\n MathLib.mulDiv(baseAmount, 10 ** quoteDecimals, 10 ** baseDecimals), rounding\n );\n }\n\n /// @dev Converts asset amount to share amount.\n function assetToShareAmount(\n uint256 assetAmount,\n uint8 assetDecimals,\n uint8 shareDecimals,\n D18 pricePoolPerAsset,\n D18 pricePoolPerShare,\n MathLib.Rounding rounding\n ) internal pure returns (uint256 shareAmount) {\n return pricePoolPerShare.reciprocalMulUint256(\n convertWithPrice(assetAmount, assetDecimals, shareDecimals, pricePoolPerAsset, MathLib.Rounding.Down),\n rounding\n );\n }\n\n /// @dev Converts share amount to asset asset amount.\n function shareToAssetAmount(\n uint256 shareAmount,\n uint8 shareDecimals,\n uint8 assetDecimals,\n D18 pricePoolPerAsset,\n D18 pricePoolPerShare,\n MathLib.Rounding rounding\n ) internal pure returns (uint256 assetAmount) {\n return convertWithReciprocalPrice(\n pricePoolPerShare.mulUint256(shareAmount, MathLib.Rounding.Down),\n shareDecimals,\n assetDecimals,\n pricePoolPerAsset,\n rounding\n );\n }\n\n /// @dev Converts pool amount to asset amount.\n function poolToAssetAmount(\n uint256 poolAmount,\n uint8 poolDecimals,\n uint8 assetDecimals,\n D18 pricePoolPerAsset,\n MathLib.Rounding rounding\n ) internal pure returns (uint256 assetAmount) {\n return convertWithReciprocalPrice(poolAmount, poolDecimals, assetDecimals, pricePoolPerAsset, rounding);\n }\n\n /// @dev Returns the asset price per share denominated in ASSET_UNIT/SHARE_UNIT\n ///\n /// @dev NOTE: Should never be used for calculating amounts due to precision loss. Instead, please refer to\n /// conversion relying on pricePoolPerShare and pricePoolPerAsset.\n function priceAssetPerShare(D18 pricePoolPerShare, D18 pricePoolPerAsset)\n internal\n pure\n returns (D18 priceAssetPerShare_)\n {\n return pricePoolPerShare / pricePoolPerAsset;\n }\n\n /// -----------------------------------------------------\n /// Private Methods\n /// -----------------------------------------------------\n\n /// @dev Returns the asset decimals\n function getAssetDecimals(address asset, uint256 tokenId) private view returns (uint8 assetDecimals) {\n return tokenId == 0 ? IERC20Metadata(asset).decimals() : IERC6909MetadataExt(asset).decimals(tokenId);\n }\n\n /// @dev When converting assets to shares using the price, all values are normalized to PRICE_DECIMALS\n /// @dev NOTE: We require all assets to have 2 <= decimals <= 18, see `PoolManager.registerAsset`\n function toPriceDecimals(uint128 _value, uint8 decimals) private pure returns (uint256) {\n if (PRICE_DECIMALS == decimals) return uint256(_value);\n return uint256(_value) * 10 ** (PRICE_DECIMALS - decimals);\n }\n\n /// @dev Converts decimals of the value from the price decimals back to the intended decimals\n /// @dev NOTE: We require all assets to have 2 <= decimals <= 18, see `PoolManager.registerAsset`\n function fromPriceDecimals(uint256 _value, uint8 decimals) private pure returns (uint128) {\n if (PRICE_DECIMALS == decimals) return _value.toUint128();\n return (_value / 10 ** (PRICE_DECIMALS - decimals)).toUint128();\n }\n}\n" + }, + "src/common/types/AccountId.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\ntype AccountId is uint32;\n\nfunction raw(AccountId accountId_) pure returns (uint32) {\n return AccountId.unwrap(accountId_);\n}\n\nusing {raw} for AccountId global;\n" + }, + "src/common/types/AssetId.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\n/// @dev Composite Id of the centrifugeId (uint16) where the asset resides\n/// and a local counter (uint64) that is part of the contract that registers the asset.\ntype AssetId is uint128;\n\nfunction isNull(AssetId assetId) pure returns (bool) {\n return AssetId.unwrap(assetId) == 0;\n}\n\nfunction addr(AssetId assetId) pure returns (address) {\n return address(uint160(AssetId.unwrap(assetId)));\n}\n\nfunction raw(AssetId assetId) pure returns (uint128) {\n return AssetId.unwrap(assetId);\n}\n\nfunction centrifugeId(AssetId assetId) pure returns (uint16) {\n return uint16(AssetId.unwrap(assetId) >> 112);\n}\n\nfunction newAssetId(uint16 centrifugeId_, uint64 counter) pure returns (AssetId) {\n return AssetId.wrap((uint128(centrifugeId_) << 112) + counter);\n}\n\nfunction newAssetId(uint32 isoCode) pure returns (AssetId) {\n return AssetId.wrap(isoCode);\n}\n\nfunction eq(AssetId a, AssetId b) pure returns (bool) {\n return a.raw() == b.raw();\n}\n\nusing {isNull, addr, raw, centrifugeId, eq} for AssetId global;\n" + }, + "src/common/types/PoolId.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\n\nusing MathLib for uint256;\n\ntype PoolId is uint64;\n\nfunction centrifugeId(PoolId poolId) pure returns (uint16) {\n return uint16(PoolId.unwrap(poolId) >> 48);\n}\n\nfunction newPoolId(uint16 centrifugeId_, uint48 localPoolId) pure returns (PoolId) {\n return PoolId.wrap((uint64(centrifugeId_) << 48) | uint64(localPoolId));\n}\n\nfunction isNull(PoolId poolId) pure returns (bool) {\n return PoolId.unwrap(poolId) == 0;\n}\n\nfunction raw(PoolId poolId) pure returns (uint64) {\n return PoolId.unwrap(poolId);\n}\n\nusing {centrifugeId, isNull, raw} for PoolId global;\n" + }, + "src/common/types/ShareClassId.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\n\ntype ShareClassId is bytes16;\n\nfunction isNull(ShareClassId scId) pure returns (bool) {\n return ShareClassId.unwrap(scId) == 0;\n}\n\nfunction equals(ShareClassId left, ShareClassId right) pure returns (bool) {\n return ShareClassId.unwrap(left) == ShareClassId.unwrap(right);\n}\n\nfunction raw(ShareClassId scId) pure returns (bytes16) {\n return ShareClassId.unwrap(scId);\n}\n\nfunction newShareClassId(PoolId poolId, uint32 index) pure returns (ShareClassId scId) {\n return ShareClassId.wrap(bytes16((uint128(PoolId.unwrap(poolId)) << 64) + index));\n}\n\nusing {isNull, raw, equals as ==} for ShareClassId global;\n" + }, + "src/hooks/FreezeOnly.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\nimport {BitmapLib} from \"src/misc/libraries/BitmapLib.sol\";\nimport {IERC165} from \"src/misc/interfaces/IERC7575.sol\";\n\nimport {IRoot} from \"src/common/interfaces/IRoot.sol\";\nimport {UpdateRestrictionType, MessageLib} from \"src/common/libraries/MessageLib.sol\";\n\nimport {IHook, HookData} from \"src/common/interfaces/IHook.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\n\nimport {IFreezable} from \"src/hooks/interfaces/IFreezable.sol\";\n\n/// @title Freeze Only\n/// @notice Hook implementation that:\n/// * Allows any non-frozen account to receive tokens and transfer tokens\n/// * Supports freezing accounts which blocks transfers both to and from them\n/// * Allows authTransferFrom calls\n///\n/// @dev The last bit of hookData is used to denote whether the account is frozen.\ncontract FreezeOnly is Auth, IFreezable, IHook {\n using BitmapLib for *;\n using MessageLib for *;\n using BytesLib for bytes;\n using CastLib for bytes32;\n\n /// @dev Least significant bit\n uint8 public constant FREEZE_BIT = 0;\n\n IRoot public immutable root;\n\n constructor(address root_, address deployer) Auth(deployer) {\n root = IRoot(root_);\n }\n\n //----------------------------------------------------------------------------------------------\n // Callback from share token\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHook\n function onERC20Transfer(address from, address to, uint256 value, HookData calldata hookData)\n external\n virtual\n returns (bytes4)\n {\n require(checkERC20Transfer(from, to, value, hookData), TransferBlocked());\n return IHook.onERC20Transfer.selector;\n }\n\n /// @inheritdoc IHook\n function onERC20AuthTransfer(\n address, /* sender */\n address, /* from */\n address, /* to */\n uint256, /* value */\n HookData calldata /* hookData */\n ) external pure returns (bytes4) {\n return IHook.onERC20AuthTransfer.selector;\n }\n\n /// @inheritdoc IHook\n function checkERC20Transfer(address from, address, /* to */ uint256, /* value */ HookData calldata hookData)\n public\n view\n returns (bool)\n {\n uint128 fromHookData = uint128(hookData.from);\n if (fromHookData.getBit(FREEZE_BIT) == true && !root.endorsed(from)) {\n // Source is frozen and not endorsed\n return false;\n }\n\n uint128 toHookData = uint128(hookData.to);\n if (toHookData.getBit(FREEZE_BIT) == true) {\n // Destination is frozen\n return false;\n }\n\n return true;\n }\n\n //----------------------------------------------------------------------------------------------\n // Restriction updates\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHook\n function updateRestriction(address token, bytes memory payload) external auth {\n UpdateRestrictionType updateId = payload.updateRestrictionType();\n\n if (updateId == UpdateRestrictionType.Freeze) {\n MessageLib.UpdateRestrictionFreeze memory m = payload.deserializeUpdateRestrictionFreeze();\n freeze(token, m.user.toAddress());\n } else if (updateId == UpdateRestrictionType.Unfreeze) {\n MessageLib.UpdateRestrictionUnfreeze memory m = payload.deserializeUpdateRestrictionUnfreeze();\n unfreeze(token, m.user.toAddress());\n } else {\n revert InvalidUpdate();\n }\n }\n\n /// @inheritdoc IFreezable\n function freeze(address token, address user) public auth {\n require(user != address(0), CannotFreezeZeroAddress());\n require(!root.endorsed(user), EndorsedUserCannotBeFrozen());\n\n uint128 hookData = uint128(IShareToken(token).hookDataOf(user));\n IShareToken(token).setHookData(user, bytes16(hookData.setBit(FREEZE_BIT, true)));\n\n emit Freeze(token, user);\n }\n\n /// @inheritdoc IFreezable\n function unfreeze(address token, address user) public auth {\n uint128 hookData = uint128(IShareToken(token).hookDataOf(user));\n IShareToken(token).setHookData(user, bytes16(hookData.setBit(FREEZE_BIT, false)));\n\n emit Unfreeze(token, user);\n }\n\n /// @inheritdoc IFreezable\n function isFrozen(address token, address user) public view returns (bool) {\n return uint128(IShareToken(token).hookDataOf(user)).getBit(FREEZE_BIT);\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-165\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC165\n function supportsInterface(bytes4 interfaceId) external pure override returns (bool) {\n return interfaceId == type(IHook).interfaceId || interfaceId == type(IERC165).interfaceId;\n }\n}\n" + }, + "src/hooks/FullRestrictions.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {BitmapLib} from \"src/misc/libraries/BitmapLib.sol\";\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\nimport {IERC165} from \"src/misc/interfaces/IERC7575.sol\";\n\nimport {UpdateRestrictionType, MessageLib} from \"src/common/libraries/MessageLib.sol\";\nimport {IRoot} from \"src/common/interfaces/IRoot.sol\";\n\nimport {IHook, HookData, ESCROW_HOOK_ID} from \"src/common/interfaces/IHook.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\n\nimport {IFreezable} from \"src/hooks/interfaces/IFreezable.sol\";\nimport {IMemberlist} from \"src/hooks/interfaces/IMemberlist.sol\";\n\n/// @title Full Restrictions\n/// @notice Hook implementation that:\n/// * Requires adding accounts to the memberlist before they can receive tokens\n/// * Supports freezing accounts which blocks transfers both to and from them\n/// * Allows authTransferFrom calls\n///\n/// @dev The first 8 bytes (uint64) of hookData is used for the memberlist valid until date,\n/// the last bit is used to denote whether the account is frozen.\ncontract FullRestrictions is Auth, IMemberlist, IFreezable, IHook {\n using BitmapLib for *;\n using MessageLib for *;\n using BytesLib for bytes;\n using CastLib for bytes32;\n\n /// @dev Least significant bit\n uint8 public constant FREEZE_BIT = 0;\n\n IRoot public immutable root;\n\n constructor(address root_, address deployer) Auth(deployer) {\n root = IRoot(root_);\n }\n\n //----------------------------------------------------------------------------------------------\n // Callback from share token\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHook\n function onERC20Transfer(address from, address to, uint256 value, HookData calldata hookData)\n external\n virtual\n returns (bytes4)\n {\n require(checkERC20Transfer(from, to, value, hookData), TransferBlocked());\n return IHook.onERC20Transfer.selector;\n }\n\n /// @inheritdoc IHook\n function onERC20AuthTransfer(\n address, /* sender */\n address, /* from */\n address, /* to */\n uint256, /* value */\n HookData calldata /* hookData */\n ) external pure returns (bytes4) {\n return IHook.onERC20AuthTransfer.selector;\n }\n\n /// @inheritdoc IHook\n function checkERC20Transfer(address from, address to, uint256, /* value */ HookData calldata hookData)\n public\n view\n returns (bool)\n {\n if (uint128(hookData.from).getBit(FREEZE_BIT) == true && !root.endorsed(from) && from != ESCROW_HOOK_ID) {\n // Source is frozen and not endorsed\n return false;\n }\n\n if (root.endorsed(to) || to == address(0) || to == ESCROW_HOOK_ID) {\n // Destination is endorsed or escrow and source was already checked, so the transfer is allowed\n return true;\n }\n\n uint128 toHookData = uint128(hookData.to);\n if (toHookData.getBit(FREEZE_BIT) == true) {\n // Destination is frozen\n return false;\n }\n\n if (toHookData >> 64 < block.timestamp) {\n // Destination is not a member\n return false;\n }\n\n return true;\n }\n\n //----------------------------------------------------------------------------------------------\n // Restriction updates\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHook\n function updateRestriction(address token, bytes memory payload) external auth {\n UpdateRestrictionType updateId = payload.updateRestrictionType();\n\n if (updateId == UpdateRestrictionType.Member) {\n MessageLib.UpdateRestrictionMember memory m = payload.deserializeUpdateRestrictionMember();\n updateMember(token, m.user.toAddress(), m.validUntil);\n } else if (updateId == UpdateRestrictionType.Freeze) {\n MessageLib.UpdateRestrictionFreeze memory m = payload.deserializeUpdateRestrictionFreeze();\n freeze(token, m.user.toAddress());\n } else if (updateId == UpdateRestrictionType.Unfreeze) {\n MessageLib.UpdateRestrictionUnfreeze memory m = payload.deserializeUpdateRestrictionUnfreeze();\n unfreeze(token, m.user.toAddress());\n } else {\n revert InvalidUpdate();\n }\n }\n\n /// @inheritdoc IFreezable\n function freeze(address token, address user) public auth {\n require(user != address(0), CannotFreezeZeroAddress());\n require(!root.endorsed(user), EndorsedUserCannotBeFrozen());\n\n uint128 hookData = uint128(IShareToken(token).hookDataOf(user));\n IShareToken(token).setHookData(user, bytes16(hookData.setBit(FREEZE_BIT, true)));\n\n emit Freeze(token, user);\n }\n\n /// @inheritdoc IFreezable\n function unfreeze(address token, address user) public auth {\n uint128 hookData = uint128(IShareToken(token).hookDataOf(user));\n IShareToken(token).setHookData(user, bytes16(hookData.setBit(FREEZE_BIT, false)));\n\n emit Unfreeze(token, user);\n }\n\n /// @inheritdoc IFreezable\n function isFrozen(address token, address user) public view returns (bool) {\n return uint128(IShareToken(token).hookDataOf(user)).getBit(FREEZE_BIT);\n }\n\n /// @inheritdoc IMemberlist\n function updateMember(address token, address user, uint64 validUntil) public auth {\n require(block.timestamp <= validUntil, InvalidValidUntil());\n require(!root.endorsed(user), EndorsedUserCannotBeUpdated());\n\n uint128 hookData = uint128(validUntil) << 64;\n hookData.setBit(FREEZE_BIT, isFrozen(token, user));\n IShareToken(token).setHookData(user, bytes16(hookData));\n\n emit UpdateMember(token, user, validUntil);\n }\n\n /// @inheritdoc IMemberlist\n function isMember(address token, address user) external view returns (bool isValid, uint64 validUntil) {\n validUntil = abi.encodePacked(IShareToken(token).hookDataOf(user)).toUint64(0);\n isValid = validUntil >= block.timestamp;\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-165\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC165\n function supportsInterface(bytes4 interfaceId) external pure override returns (bool) {\n return interfaceId == type(IHook).interfaceId || interfaceId == type(IERC165).interfaceId;\n }\n}\n" + }, + "src/hooks/RedemptionRestrictions.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\nimport {BitmapLib} from \"src/misc/libraries/BitmapLib.sol\";\nimport {IERC165} from \"src/misc/interfaces/IERC7575.sol\";\n\nimport {IRoot} from \"src/common/interfaces/IRoot.sol\";\nimport {UpdateRestrictionType, MessageLib} from \"src/common/libraries/MessageLib.sol\";\n\nimport {IHook, HookData, ESCROW_HOOK_ID} from \"src/common/interfaces/IHook.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\n\nimport {IFreezable} from \"src/hooks/interfaces/IFreezable.sol\";\nimport {IMemberlist} from \"src/hooks/interfaces/IMemberlist.sol\";\n\n/// @title Redemption Restrictions\n/// @notice Hook implementation that:\n/// * Allows any non-frozen account to receive tokens and transfer tokens\n/// * Requires accounts to be added as a member before submitting a redemption request\n/// * Supports freezing accounts which blocks transfers both to and from them\n/// * Allows authTransferFrom calls\n///\n/// @dev The first 8 bytes (uint64) of hookData is used for the memberlist valid until date,\n/// the last bit is used to denote whether the account is frozen.\ncontract RedemptionRestrictions is Auth, IMemberlist, IFreezable, IHook {\n using BitmapLib for *;\n using MessageLib for *;\n using BytesLib for bytes;\n using CastLib for bytes32;\n\n /// @dev Least significant bit\n uint8 public constant FREEZE_BIT = 0;\n\n IRoot public immutable root;\n\n constructor(address root_, address deployer) Auth(deployer) {\n root = IRoot(root_);\n }\n\n //----------------------------------------------------------------------------------------------\n // Callback from share token\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHook\n function onERC20Transfer(address from, address to, uint256 value, HookData calldata hookData)\n external\n virtual\n returns (bytes4)\n {\n require(checkERC20Transfer(from, to, value, hookData), TransferBlocked());\n return IHook.onERC20Transfer.selector;\n }\n\n /// @inheritdoc IHook\n function onERC20AuthTransfer(\n address, /* sender */\n address, /* from */\n address, /* to */\n uint256, /* value */\n HookData calldata /* hookData */\n ) external pure returns (bytes4) {\n return IHook.onERC20AuthTransfer.selector;\n }\n\n /// @inheritdoc IHook\n function checkERC20Transfer(address from, address to, uint256, /* value */ HookData calldata hookData)\n public\n view\n returns (bool)\n {\n uint128 fromHookData = uint128(hookData.from);\n if (fromHookData.getBit(FREEZE_BIT) == true && !root.endorsed(from)) {\n // Source is frozen and not endorsed\n return false;\n }\n\n uint128 toHookData = uint128(hookData.to);\n if (toHookData.getBit(FREEZE_BIT) == true) {\n // Destination is frozen\n return false;\n }\n\n if (from == address(0) && to == ESCROW_HOOK_ID) {\n // Deposit request fulfillment\n return true;\n }\n\n if (to == ESCROW_HOOK_ID && fromHookData >> 64 < block.timestamp) {\n // Destination is escrow, so it's a redemption request, and the user is not a member\n return false;\n }\n\n return true;\n }\n\n //----------------------------------------------------------------------------------------------\n // Restriction updates\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHook\n function updateRestriction(address token, bytes memory payload) external auth {\n UpdateRestrictionType updateId = payload.updateRestrictionType();\n\n if (updateId == UpdateRestrictionType.Member) {\n MessageLib.UpdateRestrictionMember memory m = payload.deserializeUpdateRestrictionMember();\n updateMember(token, m.user.toAddress(), m.validUntil);\n } else if (updateId == UpdateRestrictionType.Freeze) {\n MessageLib.UpdateRestrictionFreeze memory m = payload.deserializeUpdateRestrictionFreeze();\n freeze(token, m.user.toAddress());\n } else if (updateId == UpdateRestrictionType.Unfreeze) {\n MessageLib.UpdateRestrictionUnfreeze memory m = payload.deserializeUpdateRestrictionUnfreeze();\n unfreeze(token, m.user.toAddress());\n } else {\n revert InvalidUpdate();\n }\n }\n\n /// @inheritdoc IFreezable\n function freeze(address token, address user) public auth {\n require(user != address(0), CannotFreezeZeroAddress());\n require(!root.endorsed(user), EndorsedUserCannotBeFrozen());\n\n uint128 hookData = uint128(IShareToken(token).hookDataOf(user));\n IShareToken(token).setHookData(user, bytes16(hookData.setBit(FREEZE_BIT, true)));\n\n emit Freeze(token, user);\n }\n\n /// @inheritdoc IFreezable\n function unfreeze(address token, address user) public auth {\n uint128 hookData = uint128(IShareToken(token).hookDataOf(user));\n IShareToken(token).setHookData(user, bytes16(hookData.setBit(FREEZE_BIT, false)));\n\n emit Unfreeze(token, user);\n }\n\n /// @inheritdoc IFreezable\n function isFrozen(address token, address user) public view returns (bool) {\n return uint128(IShareToken(token).hookDataOf(user)).getBit(FREEZE_BIT);\n }\n\n /// @inheritdoc IMemberlist\n function updateMember(address token, address user, uint64 validUntil) public auth {\n require(block.timestamp <= validUntil, InvalidValidUntil());\n require(!root.endorsed(user), EndorsedUserCannotBeUpdated());\n\n uint128 hookData = uint128(validUntil) << 64;\n hookData.setBit(FREEZE_BIT, isFrozen(token, user));\n IShareToken(token).setHookData(user, bytes16(hookData));\n\n emit UpdateMember(token, user, validUntil);\n }\n\n /// @inheritdoc IMemberlist\n function isMember(address token, address user) external view returns (bool isValid, uint64 validUntil) {\n validUntil = abi.encodePacked(IShareToken(token).hookDataOf(user)).toUint64(0);\n isValid = validUntil >= block.timestamp;\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-165\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC165\n function supportsInterface(bytes4 interfaceId) external pure override returns (bool) {\n return interfaceId == type(IHook).interfaceId || interfaceId == type(IERC165).interfaceId;\n }\n}\n" + }, + "src/hooks/interfaces/IFreezable.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\ninterface IFreezable {\n // --- Events ---\n event Freeze(address indexed token, address indexed user);\n event Unfreeze(address indexed token, address indexed user);\n\n // --- Errors ---\n error CannotFreezeZeroAddress();\n error EndorsedUserCannotBeFrozen();\n\n // --- Handling freezes ---\n /// @notice Freeze a user balance. Frozen users cannot receive nor send tokens\n function freeze(address token, address user) external;\n\n /// @notice Unfreeze a user balance\n function unfreeze(address token, address user) external;\n\n /// @notice Returns whether the user's tokens are frozen\n function isFrozen(address token, address user) external view returns (bool);\n}\n" + }, + "src/hooks/interfaces/IMemberlist.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\ninterface IMemberlist {\n // --- Events ---\n event UpdateMember(address indexed token, address indexed user, uint64 validUntil);\n\n // --- Errors ---\n error InvalidValidUntil();\n error EndorsedUserCannotBeUpdated();\n\n // --- Managing members ---\n /// @notice Add a member. Non-members cannot receive tokens, but can send tokens to valid members\n /// @param validUntil Timestamp until which the user will be a valid member\n function updateMember(address token, address user, uint64 validUntil) external;\n\n /// @notice Returns whether the user is a valid member of the token\n function isMember(address token, address user) external view returns (bool isValid, uint64 validUntil);\n}\n" + }, + "src/hub/Accounting.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\n\nimport {AccountId} from \"src/common/types/AccountId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {IAccounting, JournalEntry} from \"src/hub/interfaces/IAccounting.sol\";\nimport {TransientStorageLib} from \"src/misc/libraries/TransientStorageLib.sol\";\n\n/// @notice In a transaction there can be multiple journal entries for different pools,\n/// which can be interleaved. We want entries for the same pool to share the same journal ID.\n/// So we're keeping a journal ID per pool in transient storage.\nlibrary TransientJournal {\n function journalId(PoolId poolId) internal view returns (uint256) {\n return TransientStorageLib.tloadUint256(keccak256(abi.encode(\"journalId\", poolId)));\n }\n\n function setJournalId(PoolId poolId, uint256 value) internal {\n TransientStorageLib.tstore(keccak256(abi.encode(\"journalId\", poolId)), value);\n }\n}\n\n/// @title Accounting\n/// @notice Double-entry bookkeeping system.\n/// @dev To add entries, a specific pool needs to be unlocked.\n/// When locking, the debited and credited amounts need to match.\ncontract Accounting is Auth, IAccounting {\n mapping(PoolId => mapping(AccountId => Account)) public accounts;\n\n uint128 public transient debited;\n uint128 public transient credited;\n PoolId internal transient _currentPoolId;\n mapping(PoolId => uint64) internal _poolJournalIdCounter;\n\n constructor(address deployer) Auth(deployer) {}\n\n //----------------------------------------------------------------------------------------------\n // Lock/unlock\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IAccounting\n function unlock(PoolId poolId) external auth {\n require(PoolId.unwrap(_currentPoolId) == 0, AccountingAlreadyUnlocked());\n debited = 0;\n credited = 0;\n _currentPoolId = poolId;\n\n if (TransientJournal.journalId(poolId) == 0) {\n TransientJournal.setJournalId(poolId, _generateJournalId(poolId));\n }\n emit StartJournalId(poolId, TransientJournal.journalId(poolId));\n }\n\n /// @inheritdoc IAccounting\n function lock() external auth {\n require(debited == credited, Unbalanced());\n\n emit EndJournalId(_currentPoolId, TransientJournal.journalId(_currentPoolId));\n _currentPoolId = PoolId.wrap(0);\n }\n\n //----------------------------------------------------------------------------------------------\n // Account creation & metadata\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IAccounting\n function createAccount(PoolId poolId, AccountId account, bool isDebitNormal) external auth {\n require(accounts[poolId][account].lastUpdated == 0, AccountExists());\n accounts[poolId][account] = Account(0, 0, isDebitNormal, uint64(block.timestamp), \"\");\n emit CreateAccount(poolId, account, isDebitNormal);\n }\n\n /// @inheritdoc IAccounting\n function setAccountMetadata(PoolId poolId, AccountId account, bytes calldata metadata) external auth {\n require(accounts[poolId][account].lastUpdated != 0, AccountDoesNotExist());\n accounts[poolId][account].metadata = metadata;\n emit SetAccountMetadata(poolId, account, metadata);\n }\n \n //----------------------------------------------------------------------------------------------\n // Account updates\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IAccounting\n function addDebit(AccountId account, uint128 value) public auth {\n require(!_currentPoolId.isNull(), AccountingLocked());\n\n Account storage acc = accounts[_currentPoolId][account];\n require(acc.lastUpdated != 0, AccountDoesNotExist());\n\n acc.totalDebit += value;\n debited += value;\n acc.lastUpdated = uint64(block.timestamp);\n emit Debit(_currentPoolId, account, value);\n }\n\n /// @inheritdoc IAccounting\n function addCredit(AccountId account, uint128 value) public auth {\n require(!_currentPoolId.isNull(), AccountingLocked());\n\n Account storage acc = accounts[_currentPoolId][account];\n require(acc.lastUpdated != 0, AccountDoesNotExist());\n\n acc.totalCredit += value;\n credited += value;\n acc.lastUpdated = uint64(block.timestamp);\n emit Credit(_currentPoolId, account, value);\n }\n\n /// @inheritdoc IAccounting\n function addJournal(JournalEntry[] memory debits, JournalEntry[] memory credits) external auth {\n for (uint256 i; i < debits.length; i++) {\n addDebit(debits[i].accountId, debits[i].value);\n }\n\n for (uint256 i; i < credits.length; i++) {\n addCredit(credits[i].accountId, credits[i].value);\n }\n }\n\n //----------------------------------------------------------------------------------------------\n // View methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IAccounting\n function accountValue(PoolId poolId, AccountId account) external view returns (bool /* isPositive */, uint128) {\n Account storage acc = accounts[poolId][account];\n require(acc.lastUpdated != 0, AccountDoesNotExist());\n\n if (acc.isDebitNormal) {\n // For debit-normal accounts: Value = Total Debit - Total Credit\n if (acc.totalDebit >= acc.totalCredit) {\n return (true, acc.totalDebit - acc.totalCredit);\n } else {\n return (false, acc.totalCredit - acc.totalDebit);\n }\n } else {\n // For credit-normal accounts: Value = Total Credit - Total Debit\n if (acc.totalCredit >= acc.totalDebit) {\n return (true, acc.totalCredit - acc.totalDebit);\n } else {\n return (false, acc.totalDebit - acc.totalCredit);\n }\n }\n }\n\n /// @inheritdoc IAccounting\n function exists(PoolId poolId, AccountId account) external view returns (bool) {\n return accounts[poolId][account].lastUpdated != 0;\n }\n\n function _generateJournalId(PoolId poolId) internal returns (uint256) {\n return uint256((uint256(poolId.raw()) << 128) | ++_poolJournalIdCounter[poolId]);\n }\n}\n" + }, + "src/hub/Holdings.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IERC7726} from \"src/misc/interfaces/IERC7726.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {d18, D18} from \"src/misc/types/D18.sol\";\n\nimport {PricingLib} from \"src/common/libraries/PricingLib.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {AccountId} from \"src/common/types/AccountId.sol\";\nimport {IHoldings, Holding} from \"src/hub/interfaces/IHoldings.sol\";\nimport {IHubRegistry} from \"src/hub/interfaces/IHubRegistry.sol\";\nimport {IHoldings, Holding, HoldingAccount} from \"src/hub/interfaces/IHoldings.sol\";\n\n/// @title Holdings\n/// @notice Bookkeeping of the holdings and its associated accounting IDs for each pool.\ncontract Holdings is Auth, IHoldings {\n using MathLib for uint256;\n\n IHubRegistry public immutable hubRegistry;\n\n mapping(PoolId => mapping(ShareClassId => mapping(AssetId => Holding))) public holding;\n mapping(PoolId => mapping(ShareClassId => mapping(AssetId => mapping(uint8 kind => AccountId)))) public accountId;\n\n constructor(IHubRegistry hubRegistry_, address deployer) Auth(deployer) {\n hubRegistry = hubRegistry_;\n }\n\n //----------------------------------------------------------------------------------------------\n // Holding creation & updates\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHoldings\n function create(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n IERC7726 valuation_,\n bool isLiability_,\n HoldingAccount[] memory accounts\n ) external auth {\n require(!scId.isNull(), WrongShareClassId());\n require(address(valuation_) != address(0), WrongValuation());\n\n holding[poolId][scId][assetId] = Holding(0, 0, valuation_, isLiability_);\n\n for (uint256 i; i < accounts.length; i++) {\n accountId[poolId][scId][assetId][accounts[i].kind] = accounts[i].accountId;\n }\n\n emit Create(poolId, scId, assetId, valuation_, isLiability_, accounts);\n }\n\n /// @inheritdoc IHoldings\n function setAccountId(PoolId poolId, ShareClassId scId, AssetId assetId, uint8 kind, AccountId accountId_)\n external\n auth\n {\n Holding storage holding_ = holding[poolId][scId][assetId];\n require(address(holding_.valuation) != address(0), HoldingNotFound());\n\n accountId[poolId][scId][assetId][kind] = accountId_;\n\n emit SetAccountId(poolId, scId, assetId, kind, accountId_);\n }\n\n /// @inheritdoc IHoldings\n function updateValuation(PoolId poolId, ShareClassId scId, AssetId assetId, IERC7726 valuation_) external auth {\n require(address(valuation_) != address(0), WrongValuation());\n\n Holding storage holding_ = holding[poolId][scId][assetId];\n require(address(holding_.valuation) != address(0), HoldingNotFound());\n\n holding_.valuation = valuation_;\n\n emit UpdateValuation(poolId, scId, assetId, valuation_);\n }\n\n //----------------------------------------------------------------------------------------------\n // Value updates\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHoldings\n function increase(PoolId poolId, ShareClassId scId, AssetId assetId, D18 pricePoolPerAsset, uint128 amount_)\n external\n auth\n returns (uint128 amountValue)\n {\n Holding storage holding_ = holding[poolId][scId][assetId];\n require(address(holding_.valuation) != address(0), HoldingNotFound());\n\n amountValue = PricingLib.convertWithPrice(\n amount_, hubRegistry.decimals(assetId), hubRegistry.decimals(poolId), pricePoolPerAsset\n ).toUint128();\n\n holding_.assetAmount += amount_;\n holding_.assetAmountValue += amountValue;\n\n emit Increase(poolId, scId, assetId, pricePoolPerAsset, amount_, amountValue);\n }\n\n /// @inheritdoc IHoldings\n function decrease(PoolId poolId, ShareClassId scId, AssetId assetId, D18 pricePoolPerAsset, uint128 amount_)\n external\n auth\n returns (uint128 amountValue)\n {\n Holding storage holding_ = holding[poolId][scId][assetId];\n require(address(holding_.valuation) != address(0), HoldingNotFound());\n\n amountValue = PricingLib.convertWithPrice(\n amount_, hubRegistry.decimals(assetId), hubRegistry.decimals(poolId), pricePoolPerAsset\n ).toUint128();\n\n holding_.assetAmount -= amount_;\n holding_.assetAmountValue -= amountValue;\n\n emit Decrease(poolId, scId, assetId, pricePoolPerAsset, amount_, amountValue);\n }\n\n /// @inheritdoc IHoldings\n function update(PoolId poolId, ShareClassId scId, AssetId assetId)\n external\n auth\n returns (bool isPositive, uint128 diffValue)\n {\n Holding storage holding_ = holding[poolId][scId][assetId];\n require(address(holding_.valuation) != address(0), HoldingNotFound());\n\n uint128 currentAmountValue = holding_.valuation.getQuote(\n holding_.assetAmount, assetId.addr(), hubRegistry.currency(poolId).addr()\n ).toUint128();\n\n isPositive = currentAmountValue >= holding_.assetAmountValue;\n diffValue =\n isPositive ? currentAmountValue - holding_.assetAmountValue : holding_.assetAmountValue - currentAmountValue;\n\n holding_.assetAmountValue = currentAmountValue;\n\n emit Update(poolId, scId, assetId, isPositive, diffValue);\n }\n\n //----------------------------------------------------------------------------------------------\n // View methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHoldings\n function value(PoolId poolId, ShareClassId scId, AssetId assetId) external view returns (uint128 value_) {\n Holding storage holding_ = holding[poolId][scId][assetId];\n require(address(holding_.valuation) != address(0), HoldingNotFound());\n\n return holding_.assetAmountValue;\n }\n\n /// @inheritdoc IHoldings\n function amount(PoolId poolId, ShareClassId scId, AssetId assetId) external view returns (uint128 amount_) {\n Holding storage holding_ = holding[poolId][scId][assetId];\n require(address(holding_.valuation) != address(0), HoldingNotFound());\n\n return holding_.assetAmount;\n }\n\n /// @inheritdoc IHoldings\n function valuation(PoolId poolId, ShareClassId scId, AssetId assetId) external view returns (IERC7726) {\n Holding storage holding_ = holding[poolId][scId][assetId];\n require(address(holding_.valuation) != address(0), HoldingNotFound());\n\n return holding_.valuation;\n }\n\n /// @inheritdoc IHoldings\n function isLiability(PoolId poolId, ShareClassId scId, AssetId assetId) external view returns (bool) {\n Holding storage holding_ = holding[poolId][scId][assetId];\n require(address(holding_.valuation) != address(0), HoldingNotFound());\n\n return holding_.isLiability;\n }\n\n /// @inheritdoc IHoldings\n function exists(PoolId poolId, ShareClassId scId, AssetId assetId) external view returns (bool) {\n return address(holding[poolId][scId][assetId].valuation) != address(0);\n }\n}\n" + }, + "src/hub/Hub.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {D18, d18} from \"src/misc/types/D18.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {IERC7726} from \"src/misc/interfaces/IERC7726.sol\";\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {Multicall, IMulticall} from \"src/misc/Multicall.sol\";\nimport {Recoverable} from \"src/misc/Recoverable.sol\";\n\nimport {IGateway} from \"src/common/interfaces/IGateway.sol\";\nimport {IHubGatewayHandler} from \"src/common/interfaces/IGatewayHandlers.sol\";\nimport {IPoolMessageSender} from \"src/common/interfaces/IGatewaySenders.sol\";\nimport {IHubGuardianActions} from \"src/common/interfaces/IGuardianActions.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {AccountId} from \"src/common/types/AccountId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\n\nimport {IAccounting, JournalEntry} from \"src/hub/interfaces/IAccounting.sol\";\nimport {IHubRegistry} from \"src/hub/interfaces/IHubRegistry.sol\";\nimport {IShareClassManager} from \"src/hub/interfaces/IShareClassManager.sol\";\nimport {IHoldings, HoldingAccount} from \"src/hub/interfaces/IHoldings.sol\";\nimport {IHub, AccountType} from \"src/hub/interfaces/IHub.sol\";\n\n/// @title Hub\n/// @notice Central pool management contract, that brings together all functions in one place.\n/// Pools can assign hub managers which have full rights over all actions.\n///\n/// Also acts as the central contract that routes messages from other chains to the Hub contracts.\ncontract Hub is Multicall, Auth, Recoverable, IHub, IHubGatewayHandler, IHubGuardianActions {\n using MathLib for uint256;\n\n IHubRegistry public immutable hubRegistry;\n\n IGateway public gateway;\n IHoldings public holdings;\n IAccounting public accounting;\n IPoolMessageSender public sender;\n IShareClassManager public shareClassManager;\n\n constructor(\n IShareClassManager shareClassManager_,\n IHubRegistry hubRegistry_,\n IAccounting accounting_,\n IHoldings holdings_,\n IGateway gateway_,\n address deployer\n ) Auth(deployer) {\n shareClassManager = shareClassManager_;\n hubRegistry = hubRegistry_;\n accounting = accounting_;\n holdings = holdings_;\n gateway = gateway_;\n }\n\n //----------------------------------------------------------------------------------------------\n // System methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHub\n function file(bytes32 what, address data) external {\n _auth();\n\n if (what == \"sender\") sender = IPoolMessageSender(data);\n else if (what == \"holdings\") holdings = IHoldings(data);\n else if (what == \"accounting\") accounting = IAccounting(data);\n else if (what == \"shareClassManager\") shareClassManager = IShareClassManager(data);\n else if (what == \"gateway\") gateway = IGateway(data);\n else revert FileUnrecognizedParam();\n\n emit File(what, data);\n }\n\n /// @inheritdoc IMulticall\n /// @notice performs a multicall but all messages sent in the process will be batched\n function multicall(bytes[] calldata data) public payable override {\n bool wasBatching = gateway.isBatching();\n if (!wasBatching) {\n gateway.startBatching();\n gateway.payTransaction{value: msg.value}(msg.sender);\n }\n\n super.multicall(data);\n\n if (!wasBatching) {\n gateway.endBatching();\n }\n }\n\n /// @inheritdoc IHubGuardianActions\n function createPool(PoolId poolId, address admin, AssetId currency) external payable {\n _auth();\n\n require(poolId.centrifugeId() == sender.localCentrifugeId(), InvalidPoolId());\n hubRegistry.registerPool(poolId, admin, currency);\n }\n\n //----------------------------------------------------------------------------------------------\n // Permissionless methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHub\n function notifyDeposit(PoolId poolId, ShareClassId scId, AssetId assetId, bytes32 investor, uint32 maxClaims)\n external\n payable\n {\n _pay();\n\n uint128 totalPayoutShareAmount;\n uint128 totalPaymentAssetAmount;\n uint128 cancelledAssetAmount;\n\n for (uint32 i = 0; i < maxClaims; i++) {\n (uint128 payoutShareAmount, uint128 paymentAssetAmount, uint128 cancelled, bool canClaimAgain) =\n shareClassManager.claimDeposit(poolId, scId, investor, assetId);\n\n totalPayoutShareAmount += payoutShareAmount;\n totalPaymentAssetAmount += paymentAssetAmount;\n\n // Should be written at most once with non-zero amount iff the last claimable epoch was processed and\n // the user had a pending cancellation\n // NOTE: Purposely delaying corresponding message dispatch after deposit fulfillment message\n if (cancelled > 0) {\n cancelledAssetAmount = cancelled;\n }\n\n if (!canClaimAgain) {\n break;\n }\n }\n\n sender.sendFulfilledDepositRequest(\n poolId, scId, assetId, investor, totalPaymentAssetAmount, totalPayoutShareAmount\n );\n\n // If cancellation was queued, notify about delayed cancellation\n if (cancelledAssetAmount > 0) {\n sender.sendFulfilledCancelDepositRequest(poolId, scId, assetId, investor, cancelledAssetAmount);\n }\n }\n\n /// @inheritdoc IHub\n function notifyRedeem(PoolId poolId, ShareClassId scId, AssetId assetId, bytes32 investor, uint32 maxClaims)\n external\n payable\n {\n _pay();\n\n uint128 totalPayoutAssetAmount;\n uint128 totalPaymentShareAmount;\n uint128 cancelledShareAmount;\n\n for (uint32 i = 0; i < maxClaims; i++) {\n (uint128 payoutAssetAmount, uint128 paymentShareAmount, uint128 cancelled, bool canClaimAgain) =\n shareClassManager.claimRedeem(poolId, scId, investor, assetId);\n\n totalPayoutAssetAmount += payoutAssetAmount;\n totalPaymentShareAmount += paymentShareAmount;\n\n // Should be written at most once with non-zero amount iff the last claimable epoch was processed and\n // the user had a pending cancellation\n // NOTE: Purposely delaying corresponding message dispatch after redemption fulfillment message\n if (cancelled > 0) {\n cancelledShareAmount = cancelled;\n }\n\n if (!canClaimAgain) {\n break;\n }\n }\n\n sender.sendFulfilledRedeemRequest(\n poolId, scId, assetId, investor, totalPayoutAssetAmount, totalPaymentShareAmount\n );\n\n // If cancellation was queued, notify about delayed cancellation\n if (cancelledShareAmount > 0) {\n sender.sendFulfilledCancelRedeemRequest(poolId, scId, assetId, investor, cancelledShareAmount);\n }\n }\n\n //----------------------------------------------------------------------------------------------\n // Pool admin methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHub\n function notifyPool(PoolId poolId, uint16 centrifugeId) external payable {\n _isManagerAndPaid(poolId);\n\n emit NotifyPool(centrifugeId, poolId);\n sender.sendNotifyPool(centrifugeId, poolId);\n }\n\n /// @inheritdoc IHub\n function notifyShareClass(PoolId poolId, ShareClassId scId, uint16 centrifugeId, bytes32 hook) external payable {\n _isManagerAndPaid(poolId);\n\n require(shareClassManager.exists(poolId, scId), IShareClassManager.ShareClassNotFound());\n\n (string memory name, string memory symbol, bytes32 salt) = shareClassManager.metadata(scId);\n uint8 decimals = hubRegistry.decimals(poolId);\n\n emit NotifyShareClass(centrifugeId, poolId, scId);\n sender.sendNotifyShareClass(centrifugeId, poolId, scId, name, symbol, decimals, salt, hook);\n }\n\n /// @inheritdoc IHub\n function notifyShareMetadata(PoolId poolId, ShareClassId scId, uint16 centrifugeId) public payable {\n _isManagerAndPaid(poolId);\n\n (string memory name, string memory symbol,) = shareClassManager.metadata(scId);\n\n emit NotifyShareMetadata(centrifugeId, poolId, scId, name, symbol);\n sender.sendNotifyShareMetadata(centrifugeId, poolId, scId, name, symbol);\n }\n\n /// @inheritdoc IHub\n function updateShareHook(PoolId poolId, ShareClassId scId, uint16 centrifugeId, bytes32 hook) public payable {\n _isManagerAndPaid(poolId);\n\n emit UpdateShareHook(centrifugeId, poolId, scId, hook);\n sender.sendUpdateShareHook(centrifugeId, poolId, scId, hook);\n }\n\n /// @inheritdoc IHub\n function notifySharePrice(PoolId poolId, ShareClassId scId, uint16 centrifugeId) public payable {\n _isManagerAndPaid(poolId);\n\n (, D18 poolPerShare) = shareClassManager.metrics(scId);\n\n emit NotifySharePrice(centrifugeId, poolId, scId, poolPerShare);\n sender.sendNotifyPricePoolPerShare(centrifugeId, poolId, scId, poolPerShare);\n }\n\n /// @inheritdoc IHub\n function notifyAssetPrice(PoolId poolId, ShareClassId scId, AssetId assetId) public payable {\n _isManagerAndPaid(poolId);\n D18 pricePoolPerAsset = _pricePoolPerAsset(poolId, scId, assetId);\n emit NotifyAssetPrice(assetId.centrifugeId(), poolId, scId, assetId, pricePoolPerAsset);\n sender.sendNotifyPricePoolPerAsset(poolId, scId, assetId, pricePoolPerAsset);\n }\n\n /// @inheritdoc IHub\n function triggerIssueShares(uint16 centrifugeId, PoolId poolId, ShareClassId scId, address who, uint128 shares)\n public\n payable\n {\n _isManagerAndPaid(poolId);\n\n sender.sendTriggerIssueShares(centrifugeId, poolId, scId, who, shares);\n }\n\n /// @inheritdoc IHub\n function triggerSubmitQueuedShares(uint16 centrifugeId, PoolId poolId, ShareClassId scId) public payable {\n _isManagerAndPaid(poolId);\n\n sender.sendTriggerSubmitQueuedShares(centrifugeId, poolId, scId);\n }\n\n /// @inheritdoc IHub\n function triggerSubmitQueuedAssets(PoolId poolId, ShareClassId scId, AssetId assetId) public payable {\n _isManagerAndPaid(poolId);\n\n sender.sendTriggerSubmitQueuedAssets(poolId, scId, assetId);\n }\n\n /// @inheritdoc IHub\n function setQueue(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bool enabled) public payable {\n _isManagerAndPaid(poolId);\n\n sender.sendSetQueue(centrifugeId, poolId, scId, enabled);\n }\n\n /// @inheritdoc IHub\n function setPoolMetadata(PoolId poolId, bytes calldata metadata) external payable {\n _isManager(poolId);\n\n hubRegistry.setMetadata(poolId, metadata);\n }\n\n /// @inheritdoc IHub\n function updateShareClassMetadata(PoolId poolId, ShareClassId scId, string calldata name, string calldata symbol)\n external\n payable\n {\n _isManager(poolId);\n\n shareClassManager.updateMetadata(poolId, scId, name, symbol);\n }\n\n /// @inheritdoc IHub\n function updateManager(PoolId poolId, address who, bool canManage) external payable {\n _isManager(poolId);\n\n hubRegistry.updateManager(poolId, who, canManage);\n }\n\n /// @inheritdoc IHub\n function addShareClass(PoolId poolId, string calldata name, string calldata symbol, bytes32 salt)\n external\n payable\n returns (ShareClassId scId)\n {\n _isManager(poolId);\n\n return shareClassManager.addShareClass(poolId, name, symbol, salt);\n }\n\n /// @inheritdoc IHub\n function approveDeposits(\n PoolId poolId,\n ShareClassId scId,\n AssetId depositAssetId,\n uint32 nowDepositEpochId,\n uint128 approvedAssetAmount\n ) external payable returns (uint128 pendingAssetAmount, uint128 approvedPoolAmount) {\n _isManagerAndPaid(poolId);\n D18 pricePoolPerAsset = _pricePoolPerAsset(poolId, scId, depositAssetId);\n (pendingAssetAmount, approvedPoolAmount) = shareClassManager.approveDeposits(\n poolId, scId, depositAssetId, nowDepositEpochId, approvedAssetAmount, pricePoolPerAsset\n );\n\n sender.sendApprovedDeposits(poolId, scId, depositAssetId, approvedAssetAmount, pricePoolPerAsset);\n }\n\n /// @inheritdoc IHub\n function approveRedeems(\n PoolId poolId,\n ShareClassId scId,\n AssetId payoutAssetId,\n uint32 nowRedeemEpochId,\n uint128 approvedShareAmount\n ) external payable returns (uint128 pendingShareAmount) {\n _isManager(poolId);\n\n D18 price = _pricePoolPerAsset(poolId, scId, payoutAssetId);\n (pendingShareAmount) =\n shareClassManager.approveRedeems(poolId, scId, payoutAssetId, nowRedeemEpochId, approvedShareAmount, price);\n }\n\n /// @inheritdoc IHub\n function issueShares(\n PoolId poolId,\n ShareClassId scId,\n AssetId depositAssetId,\n uint32 nowIssueEpochId,\n D18 navPoolPerShare\n ) external payable returns (uint128 issuedShareAmount, uint128 depositAssetAmount, uint128 depositPoolAmount) {\n _isManagerAndPaid(poolId);\n\n (issuedShareAmount, depositAssetAmount, depositPoolAmount) =\n shareClassManager.issueShares(poolId, scId, depositAssetId, nowIssueEpochId, navPoolPerShare);\n\n sender.sendIssuedShares(poolId, scId, depositAssetId, issuedShareAmount, navPoolPerShare);\n }\n\n /// @inheritdoc IHub\n function revokeShares(\n PoolId poolId,\n ShareClassId scId,\n AssetId payoutAssetId,\n uint32 nowRevokeEpochId,\n D18 navPoolPerShare\n ) external payable returns (uint128 revokedShareAmount, uint128 payoutAssetAmount, uint128 payoutPoolAmount) {\n _isManagerAndPaid(poolId);\n\n (revokedShareAmount, payoutAssetAmount, payoutPoolAmount) =\n shareClassManager.revokeShares(poolId, scId, payoutAssetId, nowRevokeEpochId, navPoolPerShare);\n\n sender.sendRevokedShares(poolId, scId, payoutAssetId, payoutAssetAmount, revokedShareAmount, navPoolPerShare);\n }\n\n /// @inheritdoc IHub\n function updateRestriction(PoolId poolId, ShareClassId scId, uint16 centrifugeId, bytes calldata payload)\n external\n payable\n {\n _isManagerAndPaid(poolId);\n\n require(shareClassManager.exists(poolId, scId), IShareClassManager.ShareClassNotFound());\n\n emit UpdateRestriction(centrifugeId, poolId, scId, payload);\n sender.sendUpdateRestriction(centrifugeId, poolId, scId, payload);\n }\n\n /// @inheritdoc IHub\n function updateContract(\n PoolId poolId,\n ShareClassId scId,\n uint16 centrifugeId,\n bytes32 target,\n bytes calldata payload\n ) external payable {\n _isManagerAndPaid(poolId);\n\n require(shareClassManager.exists(poolId, scId), IShareClassManager.ShareClassNotFound());\n\n emit UpdateContract(centrifugeId, poolId, scId, target, payload);\n sender.sendUpdateContract(centrifugeId, poolId, scId, target, payload);\n }\n\n /// @inheritdoc IHub\n function updatePricePerShare(PoolId poolId, ShareClassId scId, D18 navPoolPerShare) public payable {\n _isManager(poolId);\n\n shareClassManager.updatePricePerShare(poolId, scId, navPoolPerShare);\n }\n\n /// @inheritdoc IHub\n function createHolding(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n IERC7726 valuation,\n AccountId assetAccount,\n AccountId equityAccount,\n AccountId gainAccount,\n AccountId lossAccount\n ) external payable {\n _isManager(poolId);\n\n require(hubRegistry.isRegistered(assetId), IHubRegistry.AssetNotFound());\n require(\n accounting.exists(poolId, assetAccount) && accounting.exists(poolId, equityAccount)\n && accounting.exists(poolId, lossAccount) && accounting.exists(poolId, gainAccount),\n IAccounting.AccountDoesNotExist()\n );\n\n HoldingAccount[] memory accounts = new HoldingAccount[](4);\n accounts[0] = HoldingAccount(assetAccount, uint8(AccountType.Asset));\n accounts[1] = HoldingAccount(equityAccount, uint8(AccountType.Equity));\n accounts[3] = HoldingAccount(gainAccount, uint8(AccountType.Gain));\n accounts[2] = HoldingAccount(lossAccount, uint8(AccountType.Loss));\n\n holdings.create(poolId, scId, assetId, valuation, false, accounts);\n }\n\n /// @inheritdoc IHub\n function createLiability(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n IERC7726 valuation,\n AccountId expenseAccount,\n AccountId liabilityAccount\n ) external payable {\n _isManager(poolId);\n\n require(hubRegistry.isRegistered(assetId), IHubRegistry.AssetNotFound());\n require(\n accounting.exists(poolId, expenseAccount) && accounting.exists(poolId, liabilityAccount),\n IAccounting.AccountDoesNotExist()\n );\n\n HoldingAccount[] memory accounts = new HoldingAccount[](2);\n accounts[0] = HoldingAccount(expenseAccount, uint8(AccountType.Expense));\n accounts[1] = HoldingAccount(liabilityAccount, uint8(AccountType.Liability));\n\n holdings.create(poolId, scId, assetId, valuation, true, accounts);\n }\n\n /// @inheritdoc IHub\n function updateHoldingValue(PoolId poolId, ShareClassId scId, AssetId assetId) public payable {\n _isManager(poolId);\n\n accounting.unlock(poolId);\n\n (bool isPositive, uint128 diff) = holdings.update(poolId, scId, assetId);\n\n // Save a diff=0 update gas cost\n if (isPositive && diff > 0) {\n if (holdings.isLiability(poolId, scId, assetId)) {\n accounting.addCredit(holdings.accountId(poolId, scId, assetId, uint8(AccountType.Liability)), diff);\n accounting.addDebit(holdings.accountId(poolId, scId, assetId, uint8(AccountType.Expense)), diff);\n } else {\n accounting.addCredit(holdings.accountId(poolId, scId, assetId, uint8(AccountType.Gain)), diff);\n accounting.addDebit(holdings.accountId(poolId, scId, assetId, uint8(AccountType.Asset)), diff);\n }\n } else if (diff > 0) {\n if (holdings.isLiability(poolId, scId, assetId)) {\n accounting.addCredit(holdings.accountId(poolId, scId, assetId, uint8(AccountType.Expense)), diff);\n accounting.addDebit(holdings.accountId(poolId, scId, assetId, uint8(AccountType.Liability)), diff);\n } else {\n accounting.addCredit(holdings.accountId(poolId, scId, assetId, uint8(AccountType.Asset)), diff);\n accounting.addDebit(holdings.accountId(poolId, scId, assetId, uint8(AccountType.Loss)), diff);\n }\n }\n\n accounting.lock();\n }\n\n /// @inheritdoc IHub\n function updateHoldingValuation(PoolId poolId, ShareClassId scId, AssetId assetId, IERC7726 valuation)\n external\n payable\n {\n _isManager(poolId);\n\n holdings.updateValuation(poolId, scId, assetId, valuation);\n }\n\n /// @inheritdoc IHub\n function setHoldingAccountId(PoolId poolId, ShareClassId scId, AssetId assetId, uint8 kind, AccountId accountId)\n external\n payable\n {\n _isManager(poolId);\n\n holdings.setAccountId(poolId, scId, assetId, kind, accountId);\n }\n\n /// @inheritdoc IHub\n function createAccount(PoolId poolId, AccountId account, bool isDebitNormal) public payable {\n _isManager(poolId);\n\n accounting.createAccount(poolId, account, isDebitNormal);\n }\n\n /// @inheritdoc IHub\n function setAccountMetadata(PoolId poolId, AccountId account, bytes calldata metadata) external payable {\n _isManager(poolId);\n\n accounting.setAccountMetadata(poolId, account, metadata);\n }\n\n /// @inheritdoc IHub\n function updateJournal(PoolId poolId, JournalEntry[] memory debits, JournalEntry[] memory credits) external {\n _isManager(poolId);\n\n accounting.unlock(poolId);\n accounting.addJournal(debits, credits);\n accounting.lock();\n }\n\n //----------------------------------------------------------------------------------------------\n // Gateway owner methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHubGatewayHandler\n function registerAsset(AssetId assetId, uint8 decimals) external {\n _auth();\n\n hubRegistry.registerAsset(assetId, decimals);\n }\n\n /// @inheritdoc IHubGatewayHandler\n function depositRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId depositAssetId, uint128 amount)\n external\n {\n _auth();\n\n shareClassManager.requestDeposit(poolId, scId, amount, investor, depositAssetId);\n }\n\n /// @inheritdoc IHubGatewayHandler\n function redeemRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId payoutAssetId, uint128 amount)\n external\n {\n _auth();\n\n shareClassManager.requestRedeem(poolId, scId, amount, investor, payoutAssetId);\n }\n\n /// @inheritdoc IHubGatewayHandler\n function cancelDepositRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId depositAssetId)\n external\n {\n _auth();\n\n uint128 cancelledAssetAmount = shareClassManager.cancelDepositRequest(poolId, scId, investor, depositAssetId);\n\n // Cancellation might have been queued such that it will be executed in the future during claiming\n if (cancelledAssetAmount > 0) {\n sender.sendFulfilledCancelDepositRequest(poolId, scId, depositAssetId, investor, cancelledAssetAmount);\n }\n }\n\n /// @inheritdoc IHubGatewayHandler\n function cancelRedeemRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId payoutAssetId) external {\n _auth();\n\n uint128 cancelledShareAmount = shareClassManager.cancelRedeemRequest(poolId, scId, investor, payoutAssetId);\n\n // Cancellation might have been queued such that it will be executed in the future during claiming\n if (cancelledShareAmount > 0) {\n sender.sendFulfilledCancelRedeemRequest(poolId, scId, payoutAssetId, investor, cancelledShareAmount);\n }\n }\n\n /// @inheritdoc IHubGatewayHandler\n function updateHoldingAmount(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n uint128 amount,\n D18 pricePoolPerAsset,\n bool isIncrease\n ) external {\n _auth();\n\n accounting.unlock(poolId);\n\n bool isLiability = holdings.isLiability(poolId, scId, assetId);\n AccountType debitAccountType = isLiability ? AccountType.Expense : AccountType.Asset;\n AccountType creditAccountType = isLiability ? AccountType.Liability : AccountType.Equity;\n\n if (isIncrease) {\n uint128 value = holdings.increase(poolId, scId, assetId, pricePoolPerAsset, amount);\n accounting.addDebit(holdings.accountId(poolId, scId, assetId, uint8(debitAccountType)), value);\n accounting.addCredit(holdings.accountId(poolId, scId, assetId, uint8(creditAccountType)), value);\n } else {\n uint128 value = holdings.decrease(poolId, scId, assetId, pricePoolPerAsset, amount);\n accounting.addDebit(holdings.accountId(poolId, scId, assetId, uint8(creditAccountType)), value);\n accounting.addCredit(holdings.accountId(poolId, scId, assetId, uint8(debitAccountType)), value);\n }\n\n accounting.lock();\n }\n\n /// @inheritdoc IHubGatewayHandler\n function increaseShareIssuance(PoolId poolId, ShareClassId scId, uint128 amount) external {\n _auth();\n\n shareClassManager.increaseShareClassIssuance(poolId, scId, amount);\n }\n\n /// @inheritdoc IHubGatewayHandler\n function decreaseShareIssuance(PoolId poolId, ShareClassId scId, uint128 amount) external {\n _auth();\n\n shareClassManager.decreaseShareClassIssuance(poolId, scId, amount);\n }\n\n //----------------------------------------------------------------------------------------------\n // Internal methods\n //----------------------------------------------------------------------------------------------\n\n /// @dev Ensure the sender is authorized\n function _auth() internal auth {}\n\n /// @dev Ensure the method can be used without reentrancy issues, and the sender is a pool admin\n function _isManager(PoolId poolId) internal protected {\n require(hubRegistry.manager(poolId, msg.sender), IHub.NotManager());\n }\n\n /// @dev Ensure the sender is authorized\n function _isManagerAndPaid(PoolId poolId) internal {\n _isManager(poolId);\n _pay();\n }\n\n /// @notice Send native tokens to the gateway for transaction payment if it's not in a multicall.\n function _pay() internal {\n if (!gateway.isBatching()) {\n gateway.payTransaction{value: msg.value}(msg.sender);\n }\n }\n\n function _pricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId) internal view returns (D18) {\n AssetId poolCurrency = hubRegistry.currency(poolId);\n // NOTE: We assume symmetric prices are provided by holdings valuation\n IERC7726 valuation = holdings.valuation(poolId, scId, assetId);\n\n // Retrieve amount of 1 asset unit in pool currency\n uint128 assetUnitAmount = (10 ** hubRegistry.decimals(assetId.raw())).toUint128();\n uint128 poolUnitAmount = (10 ** hubRegistry.decimals(poolCurrency.raw())).toUint128();\n uint128 poolAmountPerAsset =\n valuation.getQuote(assetUnitAmount, assetId.addr(), poolCurrency.addr()).toUint128();\n\n // Retrieve price by normalizing by pool denomination\n return d18(poolAmountPerAsset, poolUnitAmount);\n }\n}\n" + }, + "src/hub/HubRegistry.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {IERC6909Decimals} from \"src/misc/interfaces/IERC6909.sol\";\n\nimport {PoolId, newPoolId} from \"src/common/types/PoolId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {IHubRegistry} from \"src/hub/interfaces/IHubRegistry.sol\";\n\n/// @title Hub Registry\n/// @notice Registry of all known pools, currencies, and assets.\ncontract HubRegistry is Auth, IHubRegistry {\n using MathLib for uint256;\n\n mapping(AssetId => uint8) internal _decimals;\n\n mapping(PoolId => bytes) public metadata;\n mapping(PoolId => AssetId) public currency;\n mapping(bytes32 => address) public dependency;\n mapping(PoolId => mapping(address => bool)) public manager;\n\n constructor(address deployer) Auth(deployer) {}\n\n //----------------------------------------------------------------------------------------------\n // Registration methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHubRegistry\n function registerAsset(AssetId assetId, uint8 decimals_) external auth {\n require(_decimals[assetId] == 0, AssetAlreadyRegistered());\n\n _decimals[assetId] = decimals_;\n\n emit NewAsset(assetId, decimals_);\n }\n\n /// @inheritdoc IHubRegistry\n function registerPool(PoolId poolId_, address manager_, AssetId currency_) external auth {\n require(manager_ != address(0), EmptyAccount());\n require(!currency_.isNull(), EmptyCurrency());\n require(currency[poolId_].isNull(), PoolAlreadyRegistered());\n\n manager[poolId_][manager_] = true;\n currency[poolId_] = currency_;\n\n emit NewPool(poolId_, manager_, currency_);\n }\n\n //----------------------------------------------------------------------------------------------\n // Update methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHubRegistry\n function updateManager(PoolId poolId_, address manager_, bool canManage) external auth {\n require(exists(poolId_), NonExistingPool(poolId_));\n require(manager_ != address(0), EmptyAccount());\n\n manager[poolId_][manager_] = canManage;\n\n emit UpdateManager(poolId_, manager_, canManage);\n }\n\n /// @inheritdoc IHubRegistry\n function setMetadata(PoolId poolId_, bytes calldata metadata_) external auth {\n require(exists(poolId_), NonExistingPool(poolId_));\n\n metadata[poolId_] = metadata_;\n\n emit SetMetadata(poolId_, metadata_);\n }\n\n /// @inheritdoc IHubRegistry\n function updateDependency(bytes32 what, address dependency_) external auth {\n dependency[what] = dependency_;\n\n emit UpdateDependency(what, dependency_);\n }\n\n /// @inheritdoc IHubRegistry\n function updateCurrency(PoolId poolId_, AssetId currency_) external auth {\n require(exists(poolId_), NonExistingPool(poolId_));\n require(!currency_.isNull(), EmptyCurrency());\n\n currency[poolId_] = currency_;\n\n emit UpdateCurrency(poolId_, currency_);\n }\n\n //----------------------------------------------------------------------------------------------\n // View methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IHubRegistry\n function poolId(uint16 centrifugeId, uint48 postfix) public pure returns (PoolId poolId_) {\n poolId_ = newPoolId(centrifugeId, postfix);\n }\n\n /// @inheritdoc IHubRegistry\n function decimals(AssetId assetId) public view returns (uint8 decimals_) {\n decimals_ = _decimals[assetId];\n require(decimals_ > 0, AssetNotFound());\n }\n\n /// @inheritdoc IHubRegistry\n function decimals(PoolId poolId_) public view returns (uint8 decimals_) {\n decimals_ = _decimals[currency[poolId_]];\n require(decimals_ > 0, AssetNotFound());\n }\n\n /// @inheritdoc IERC6909Decimals\n function decimals(uint256 asset_) external view returns (uint8 decimals_) {\n decimals_ = _decimals[AssetId.wrap(asset_.toUint128())];\n require(decimals_ > 0, AssetNotFound());\n }\n\n /// @inheritdoc IHubRegistry\n function exists(PoolId poolId_) public view returns (bool) {\n return !currency[poolId_].isNull();\n }\n\n /// @inheritdoc IHubRegistry\n function isRegistered(AssetId assetId) public view returns (bool) {\n return _decimals[assetId] != 0;\n }\n}\n" + }, + "src/hub/ShareClassManager.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {D18, d18} from \"src/misc/types/D18.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {ShareClassId, newShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {PricingLib} from \"src/common/libraries/PricingLib.sol\";\n\nimport {IHubRegistry} from \"src/hub/interfaces/IHubRegistry.sol\";\nimport {\n IShareClassManager,\n EpochInvestAmounts,\n EpochRedeemAmounts,\n UserOrder,\n ShareClassMetadata,\n ShareClassMetrics,\n QueuedOrder,\n RequestType,\n EpochId\n} from \"src/hub/interfaces/IShareClassManager.sol\";\n\n/// @title Share Class Manager\n/// @notice Manager for the share classes of a pool, and the core logic for tracking, approving, and fulfilling\n/// requests.\ncontract ShareClassManager is Auth, IShareClassManager {\n using MathLib for *;\n using CastLib for *;\n using BytesLib for bytes;\n\n IHubRegistry public immutable hubRegistry;\n\n // Share classes\n mapping(bytes32 salt => bool) public salts;\n mapping(PoolId poolId => uint32) public shareClassCount;\n mapping(ShareClassId scId => ShareClassMetrics) public metrics;\n mapping(ShareClassId scId => ShareClassMetadata) public metadata;\n mapping(PoolId poolId => mapping(ShareClassId => bool)) public shareClassIds;\n\n // Epochs\n mapping(ShareClassId scId => mapping(AssetId assetId => EpochId)) public epochId;\n mapping(ShareClassId scId => mapping(AssetId assetId => mapping(uint32 epochId_ => EpochInvestAmounts epoch)))\n public epochInvestAmounts;\n mapping(ShareClassId scId => mapping(AssetId assetId => mapping(uint32 epochId_ => EpochRedeemAmounts epoch)))\n public epochRedeemAmounts;\n\n // Pending requests\n mapping(ShareClassId scId => mapping(AssetId payoutAssetId => uint128 pending)) public pendingRedeem;\n mapping(ShareClassId scId => mapping(AssetId depositAssetId => uint128 pending)) public pendingDeposit;\n mapping(ShareClassId scId => mapping(AssetId payoutAssetId => mapping(bytes32 investor => UserOrder pending)))\n public redeemRequest;\n mapping(ShareClassId scId => mapping(AssetId depositAssetId => mapping(bytes32 investor => UserOrder pending)))\n public depositRequest;\n\n // Queued requests\n mapping(ShareClassId scId => mapping(AssetId payoutAssetId => mapping(bytes32 investor => QueuedOrder queued)))\n public queuedRedeemRequest;\n mapping(ShareClassId scId => mapping(AssetId depositAssetId => mapping(bytes32 investor => QueuedOrder queued)))\n public queuedDepositRequest;\n\n constructor(IHubRegistry hubRegistry_, address deployer) Auth(deployer) {\n hubRegistry = hubRegistry_;\n }\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IShareClassManager\n function addShareClass(PoolId poolId, string calldata name, string calldata symbol, bytes32 salt)\n external\n auth\n returns (ShareClassId scId_)\n {\n scId_ = previewNextShareClassId(poolId);\n\n uint32 index = ++shareClassCount[poolId];\n shareClassIds[poolId][scId_] = true;\n\n _updateMetadata(scId_, name, symbol, salt);\n\n emit AddShareClass(poolId, scId_, index, name, symbol, salt);\n }\n\n //----------------------------------------------------------------------------------------------\n // Incoming requests\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IShareClassManager\n function requestDeposit(PoolId poolId, ShareClassId scId_, uint128 amount, bytes32 investor, AssetId depositAssetId)\n external\n auth\n {\n require(exists(poolId, scId_), ShareClassNotFound());\n\n // NOTE: CV ensures amount > 0\n _updatePending(poolId, scId_, amount, true, investor, depositAssetId, RequestType.Deposit);\n }\n\n /// @inheritdoc IShareClassManager\n function cancelDepositRequest(PoolId poolId, ShareClassId scId_, bytes32 investor, AssetId depositAssetId)\n external\n auth\n returns (uint128 cancelledAssetAmount)\n {\n require(exists(poolId, scId_), ShareClassNotFound());\n\n uint128 cancellingAmount = depositRequest[scId_][depositAssetId][investor].pending;\n\n return _updatePending(poolId, scId_, cancellingAmount, false, investor, depositAssetId, RequestType.Deposit);\n }\n\n /// @inheritdoc IShareClassManager\n function requestRedeem(PoolId poolId, ShareClassId scId_, uint128 amount, bytes32 investor, AssetId payoutAssetId)\n external\n auth\n {\n require(exists(poolId, scId_), ShareClassNotFound());\n\n // NOTE: CV ensures amount > 0\n _updatePending(poolId, scId_, amount, true, investor, payoutAssetId, RequestType.Redeem);\n }\n\n /// @inheritdoc IShareClassManager\n function cancelRedeemRequest(PoolId poolId, ShareClassId scId_, bytes32 investor, AssetId payoutAssetId)\n external\n auth\n returns (uint128 cancelledShareAmount)\n {\n require(exists(poolId, scId_), ShareClassNotFound());\n\n uint128 cancellingAmount = redeemRequest[scId_][payoutAssetId][investor].pending;\n\n return _updatePending(poolId, scId_, cancellingAmount, false, investor, payoutAssetId, RequestType.Redeem);\n }\n\n //----------------------------------------------------------------------------------------------\n // Manager actions\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IShareClassManager\n function approveDeposits(\n PoolId poolId,\n ShareClassId scId_,\n AssetId depositAssetId,\n uint32 nowDepositEpochId,\n uint128 approvedAssetAmount,\n D18 pricePoolPerAsset\n ) external auth returns (uint128 pendingAssetAmount, uint128 approvedPoolAmount) {\n require(exists(poolId, scId_), ShareClassNotFound());\n require(\n nowDepositEpochId == nowDepositEpoch(scId_, depositAssetId),\n EpochNotInSequence(nowDepositEpochId, nowDepositEpoch(scId_, depositAssetId))\n );\n\n // Limit in case approved > pending due to race condition of FM approval and async incoming requests\n pendingAssetAmount = pendingDeposit[scId_][depositAssetId];\n require(approvedAssetAmount <= pendingAssetAmount, InsufficientPending());\n require(approvedAssetAmount > 0, ZeroApprovalAmount());\n\n approvedPoolAmount = PricingLib.convertWithPrice(\n approvedAssetAmount, hubRegistry.decimals(depositAssetId), hubRegistry.decimals(poolId), pricePoolPerAsset\n ).toUint128();\n\n // Update epoch data\n EpochInvestAmounts storage epochAmounts = epochInvestAmounts[scId_][depositAssetId][nowDepositEpochId];\n epochAmounts.approvedAssetAmount = approvedAssetAmount;\n epochAmounts.approvedPoolAmount = approvedPoolAmount;\n epochAmounts.pendingAssetAmount = pendingAssetAmount;\n epochAmounts.pricePoolPerAsset = pricePoolPerAsset;\n\n // Reduce pending\n pendingDeposit[scId_][depositAssetId] -= approvedAssetAmount;\n pendingAssetAmount -= approvedAssetAmount;\n\n epochId[scId_][depositAssetId].deposit = nowDepositEpochId;\n emit ApproveDeposits(\n poolId,\n scId_,\n depositAssetId,\n nowDepositEpochId,\n approvedPoolAmount,\n approvedAssetAmount,\n pendingAssetAmount\n );\n }\n\n /// @inheritdoc IShareClassManager\n function approveRedeems(\n PoolId poolId,\n ShareClassId scId_,\n AssetId payoutAssetId,\n uint32 nowRedeemEpochId,\n uint128 approvedShareAmount,\n D18 pricePoolPerAsset\n ) external auth returns (uint128 pendingShareAmount) {\n require(exists(poolId, scId_), ShareClassNotFound());\n require(\n nowRedeemEpochId == nowRedeemEpoch(scId_, payoutAssetId),\n EpochNotInSequence(nowRedeemEpochId, nowRedeemEpoch(scId_, payoutAssetId))\n );\n\n // Limit in case approved > pending due to race condition of FM approval and async incoming requests\n pendingShareAmount = pendingRedeem[scId_][payoutAssetId];\n require(approvedShareAmount <= pendingShareAmount, InsufficientPending());\n require(approvedShareAmount > 0, ZeroApprovalAmount());\n\n // Update epoch data\n EpochRedeemAmounts storage epochAmounts = epochRedeemAmounts[scId_][payoutAssetId][nowRedeemEpochId];\n epochAmounts.approvedShareAmount = approvedShareAmount;\n epochAmounts.pendingShareAmount = pendingShareAmount;\n epochAmounts.pricePoolPerAsset = pricePoolPerAsset;\n\n // Reduce pending\n pendingRedeem[scId_][payoutAssetId] -= approvedShareAmount;\n pendingShareAmount -= approvedShareAmount;\n epochId[scId_][payoutAssetId].redeem = nowRedeemEpochId;\n emit ApproveRedeems(poolId, scId_, payoutAssetId, nowRedeemEpochId, approvedShareAmount, pendingShareAmount);\n }\n\n /// @inheritdoc IShareClassManager\n function issueShares(\n PoolId poolId,\n ShareClassId scId_,\n AssetId depositAssetId,\n uint32 nowIssueEpochId,\n D18 navPoolPerShare\n ) external auth returns (uint128 issuedShareAmount, uint128 depositAssetAmount, uint128 depositPoolAmount) {\n require(exists(poolId, scId_), ShareClassNotFound());\n require(nowIssueEpochId <= epochId[scId_][depositAssetId].deposit, EpochNotFound());\n require(\n nowIssueEpochId == nowIssueEpoch(scId_, depositAssetId),\n EpochNotInSequence(nowIssueEpochId, nowIssueEpoch(scId_, depositAssetId))\n );\n\n EpochInvestAmounts storage epochAmounts = epochInvestAmounts[scId_][depositAssetId][nowIssueEpochId];\n epochAmounts.navPoolPerShare = navPoolPerShare;\n\n issuedShareAmount = PricingLib.assetToShareAmount(\n epochAmounts.approvedAssetAmount,\n hubRegistry.decimals(depositAssetId),\n hubRegistry.decimals(poolId),\n epochAmounts.pricePoolPerAsset,\n navPoolPerShare,\n MathLib.Rounding.Down\n ).toUint128();\n\n metrics[scId_].totalIssuance += issuedShareAmount;\n epochAmounts.issuedAt = block.timestamp.toUint64();\n epochId[scId_][depositAssetId].issue = nowIssueEpochId;\n\n depositAssetAmount = epochAmounts.approvedAssetAmount;\n depositPoolAmount = epochAmounts.approvedPoolAmount;\n\n emit IssueShares(\n poolId,\n scId_,\n depositAssetId,\n nowIssueEpochId,\n navPoolPerShare,\n PricingLib.priceAssetPerShare(epochAmounts.navPoolPerShare, epochAmounts.pricePoolPerAsset),\n issuedShareAmount\n );\n }\n\n /// @inheritdoc IShareClassManager\n function revokeShares(\n PoolId poolId,\n ShareClassId scId_,\n AssetId payoutAssetId,\n uint32 nowRevokeEpochId,\n D18 navPoolPerShare\n ) external auth returns (uint128 revokedShareAmount, uint128 payoutAssetAmount, uint128 payoutPoolAmount) {\n require(exists(poolId, scId_), ShareClassNotFound());\n require(nowRevokeEpochId <= epochId[scId_][payoutAssetId].redeem, EpochNotFound());\n require(\n nowRevokeEpochId == nowRevokeEpoch(scId_, payoutAssetId),\n EpochNotInSequence(nowRevokeEpochId, nowRevokeEpoch(scId_, payoutAssetId))\n );\n\n EpochRedeemAmounts storage epochAmounts = epochRedeemAmounts[scId_][payoutAssetId][nowRevokeEpochId];\n epochAmounts.navPoolPerShare = navPoolPerShare;\n\n require(epochAmounts.approvedShareAmount <= metrics[scId_].totalIssuance, RevokeMoreThanIssued());\n\n // NOTE: shares and pool currency have the same decimals - no conversion needed!\n payoutPoolAmount = navPoolPerShare.mulUint128(epochAmounts.approvedShareAmount, MathLib.Rounding.Down);\n\n payoutAssetAmount = PricingLib.poolToAssetAmount(\n payoutPoolAmount,\n hubRegistry.decimals(poolId),\n hubRegistry.decimals(payoutAssetId),\n epochAmounts.pricePoolPerAsset,\n MathLib.Rounding.Down\n ).toUint128();\n revokedShareAmount = epochAmounts.approvedShareAmount;\n\n metrics[scId_].totalIssuance -= epochAmounts.approvedShareAmount;\n epochAmounts.payoutAssetAmount = payoutAssetAmount;\n epochAmounts.revokedAt = block.timestamp.toUint64();\n epochId[scId_][payoutAssetId].revoke = nowRevokeEpochId;\n\n emit RevokeShares(\n poolId,\n scId_,\n payoutAssetId,\n nowRevokeEpochId,\n navPoolPerShare,\n PricingLib.priceAssetPerShare(epochAmounts.navPoolPerShare, epochAmounts.pricePoolPerAsset),\n epochAmounts.approvedShareAmount,\n payoutAssetAmount,\n payoutPoolAmount\n );\n }\n\n /// @inheritdoc IShareClassManager\n function updatePricePerShare(PoolId poolId, ShareClassId scId_, D18 navPoolPerShare) external auth {\n require(exists(poolId, scId_), ShareClassNotFound());\n\n ShareClassMetrics storage m = metrics[scId_];\n m.navPerShare = navPoolPerShare;\n emit UpdateShareClass(poolId, scId_, navPoolPerShare);\n }\n\n /// @inheritdoc IShareClassManager\n function updateMetadata(PoolId poolId, ShareClassId scId_, string calldata name, string calldata symbol)\n external\n auth\n {\n require(exists(poolId, scId_), ShareClassNotFound());\n\n _updateMetadata(scId_, name, symbol, bytes32(0));\n\n emit UpdateMetadata(poolId, scId_, name, symbol);\n }\n\n /// @inheritdoc IShareClassManager\n function increaseShareClassIssuance(PoolId poolId, ShareClassId scId_, uint128 amount) external auth {\n require(exists(poolId, scId_), ShareClassNotFound());\n\n uint128 newIssuance = metrics[scId_].totalIssuance + amount;\n metrics[scId_].totalIssuance = newIssuance;\n\n emit RemoteIssueShares(poolId, scId_, amount);\n }\n\n /// @inheritdoc IShareClassManager\n function decreaseShareClassIssuance(PoolId poolId, ShareClassId scId_, uint128 amount) external auth {\n require(exists(poolId, scId_), ShareClassNotFound());\n require(metrics[scId_].totalIssuance >= amount, DecreaseMoreThanIssued());\n\n uint128 newIssuance = metrics[scId_].totalIssuance - amount;\n metrics[scId_].totalIssuance = newIssuance;\n\n emit RemoteRevokeShares(poolId, scId_, amount);\n }\n\n //----------------------------------------------------------------------------------------------\n // Claiming methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IShareClassManager\n function claimDeposit(PoolId poolId, ShareClassId scId_, bytes32 investor, AssetId depositAssetId)\n public\n auth\n returns (\n uint128 payoutShareAmount,\n uint128 paymentAssetAmount,\n uint128 cancelledAssetAmount,\n bool canClaimAgain\n )\n {\n require(exists(poolId, scId_), ShareClassNotFound());\n\n UserOrder storage userOrder = depositRequest[scId_][depositAssetId][investor];\n require(userOrder.pending > 0, NoOrderFound());\n require(userOrder.lastUpdate <= epochId[scId_][depositAssetId].issue, IssuanceRequired());\n canClaimAgain = userOrder.lastUpdate < epochId[scId_][depositAssetId].issue;\n EpochInvestAmounts storage epochAmounts = epochInvestAmounts[scId_][depositAssetId][userOrder.lastUpdate];\n\n paymentAssetAmount = epochAmounts.approvedAssetAmount == 0\n ? 0\n : userOrder.pending.mulDiv(epochAmounts.approvedAssetAmount, epochAmounts.pendingAssetAmount).toUint128();\n\n // NOTE: Due to precision loss, the sum of claimable user amounts is leq than the amount of minted share class\n // tokens corresponding to the approved share amount (instead of equality). I.e., it is possible for an epoch to\n // have an excess of a share class tokens which cannot be claimed by anyone.\n // This excess is at most n-1 share tokens for an epoch with n claimable users.\n if (paymentAssetAmount > 0) {\n uint256 paymentPoolAmount = PricingLib.convertWithPrice(\n paymentAssetAmount,\n hubRegistry.decimals(depositAssetId),\n hubRegistry.decimals(poolId),\n epochAmounts.pricePoolPerAsset\n );\n payoutShareAmount =\n epochAmounts.navPoolPerShare.reciprocalMulUint256(paymentPoolAmount, MathLib.Rounding.Down).toUint128();\n\n userOrder.pending -= paymentAssetAmount;\n }\n\n emit ClaimDeposit(\n poolId,\n scId_,\n userOrder.lastUpdate,\n investor,\n depositAssetId,\n paymentAssetAmount,\n userOrder.pending,\n payoutShareAmount,\n epochAmounts.issuedAt\n );\n\n // If there is nothing to claim anymore we can short circuit to the latest epoch\n if (userOrder.pending == 0) {\n // The current epoch is always one step ahead of the stored one\n userOrder.lastUpdate = nowDepositEpoch(scId_, depositAssetId);\n canClaimAgain = false;\n } else {\n userOrder.lastUpdate += 1;\n }\n\n // If user claimed up to latest approval epoch, move queued to pending\n if (userOrder.lastUpdate == nowDepositEpoch(scId_, depositAssetId)) {\n cancelledAssetAmount =\n _postClaimUpdateQueued(poolId, scId_, investor, depositAssetId, userOrder, RequestType.Deposit);\n }\n }\n\n /// @inheritdoc IShareClassManager\n function claimRedeem(PoolId poolId, ShareClassId scId_, bytes32 investor, AssetId payoutAssetId)\n public\n auth\n returns (\n uint128 payoutAssetAmount,\n uint128 paymentShareAmount,\n uint128 cancelledShareAmount,\n bool canClaimAgain\n )\n {\n require(exists(poolId, scId_), ShareClassNotFound());\n\n UserOrder storage userOrder = redeemRequest[scId_][payoutAssetId][investor];\n require(userOrder.pending > 0, NoOrderFound());\n require(userOrder.lastUpdate <= epochId[scId_][payoutAssetId].revoke, RevocationRequired());\n canClaimAgain = userOrder.lastUpdate < epochId[scId_][payoutAssetId].revoke;\n\n EpochRedeemAmounts storage epochAmounts = epochRedeemAmounts[scId_][payoutAssetId][userOrder.lastUpdate];\n\n paymentShareAmount = epochAmounts.approvedShareAmount == 0\n ? 0\n : userOrder.pending.mulDiv(epochAmounts.approvedShareAmount, epochAmounts.pendingShareAmount).toUint128();\n\n // NOTE: Due to precision loss, the sum of claimable user amounts is leq than the amount of minted share class\n // tokens corresponding to the approved share amount (instead of equality). I.e., it is possible for an epoch to\n // have an excess of a share class tokens which cannot be claimed by anyone.\n // This excess is at most n-1 share tokens for an epoch with n claimable users.\n if (paymentShareAmount > 0) {\n payoutAssetAmount = PricingLib.shareToAssetAmount(\n paymentShareAmount,\n hubRegistry.decimals(poolId),\n hubRegistry.decimals(payoutAssetId),\n epochAmounts.pricePoolPerAsset,\n epochAmounts.navPoolPerShare,\n MathLib.Rounding.Down\n ).toUint128();\n\n userOrder.pending -= paymentShareAmount;\n }\n\n emit ClaimRedeem(\n poolId,\n scId_,\n userOrder.lastUpdate,\n investor,\n payoutAssetId,\n paymentShareAmount,\n userOrder.pending,\n payoutAssetAmount,\n epochAmounts.revokedAt\n );\n\n // If there is nothing to claim anymore we can short circuit the in between epochs\n if (userOrder.pending == 0) {\n // The current epoch is always one step ahead of the stored one\n userOrder.lastUpdate = nowRedeemEpoch(scId_, payoutAssetId);\n canClaimAgain = false;\n } else {\n userOrder.lastUpdate += 1;\n }\n\n if (userOrder.lastUpdate == nowRedeemEpoch(scId_, payoutAssetId)) {\n cancelledShareAmount =\n _postClaimUpdateQueued(poolId, scId_, investor, payoutAssetId, userOrder, RequestType.Redeem);\n }\n }\n\n //----------------------------------------------------------------------------------------------\n // View methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IShareClassManager\n function previewNextShareClassId(PoolId poolId) public view returns (ShareClassId scId) {\n return newShareClassId(poolId, shareClassCount[poolId] + 1);\n }\n\n /// @inheritdoc IShareClassManager\n function previewShareClassId(PoolId poolId, uint32 index) public pure returns (ShareClassId scId) {\n return newShareClassId(poolId, index);\n }\n\n /// @inheritdoc IShareClassManager\n function exists(PoolId poolId, ShareClassId scId_) public view returns (bool) {\n return shareClassIds[poolId][scId_];\n }\n\n /// @inheritdoc IShareClassManager\n function nowDepositEpoch(ShareClassId scId_, AssetId depositAssetId) public view returns (uint32) {\n return epochId[scId_][depositAssetId].deposit + 1;\n }\n\n /// @inheritdoc IShareClassManager\n function nowIssueEpoch(ShareClassId scId_, AssetId depositAssetId) public view returns (uint32) {\n return epochId[scId_][depositAssetId].issue + 1;\n }\n\n /// @inheritdoc IShareClassManager\n function nowRedeemEpoch(ShareClassId scId_, AssetId depositAssetId) public view returns (uint32) {\n return epochId[scId_][depositAssetId].redeem + 1;\n }\n\n /// @inheritdoc IShareClassManager\n function nowRevokeEpoch(ShareClassId scId_, AssetId depositAssetId) public view returns (uint32) {\n return epochId[scId_][depositAssetId].revoke + 1;\n }\n\n /// @inheritdoc IShareClassManager\n function maxDepositClaims(ShareClassId scId_, bytes32 investor, AssetId depositAssetId)\n public\n view\n returns (uint32)\n {\n return _maxClaims(depositRequest[scId_][depositAssetId][investor], epochId[scId_][depositAssetId].deposit);\n }\n\n /// @inheritdoc IShareClassManager\n function maxRedeemClaims(ShareClassId scId_, bytes32 investor, AssetId payoutAssetId)\n public\n view\n returns (uint32)\n {\n return _maxClaims(redeemRequest[scId_][payoutAssetId][investor], epochId[scId_][payoutAssetId].redeem);\n }\n\n function _maxClaims(UserOrder memory userOrder, uint32 lastEpoch) private pure returns (uint32) {\n // User order either not set or not processed\n if (userOrder.pending == 0 || userOrder.lastUpdate > lastEpoch) {\n return 0;\n }\n\n return lastEpoch - userOrder.lastUpdate + 1;\n }\n\n //----------------------------------------------------------------------------------------------\n // Internal methods\n //----------------------------------------------------------------------------------------------\n\n function _updateMetadata(ShareClassId scId_, string calldata name, string calldata symbol, bytes32 salt) private {\n uint256 nameLen = bytes(name).length;\n require(nameLen > 0 && nameLen <= 128, InvalidMetadataName());\n\n uint256 symbolLen = bytes(symbol).length;\n require(symbolLen > 0 && symbolLen <= 32, InvalidMetadataSymbol());\n\n ShareClassMetadata storage meta = metadata[scId_];\n\n // Ensure that the salt is not being updated or is being set for the first time\n require(\n (salt == bytes32(0) && meta.salt != bytes32(0)) || (salt != bytes32(0) && meta.salt == bytes32(0)),\n InvalidSalt()\n );\n\n if (salt != bytes32(0) && meta.salt == bytes32(0)) {\n require(!salts[salt], AlreadyUsedSalt());\n salts[salt] = true;\n meta.salt = salt;\n }\n\n meta.name = name;\n meta.symbol = symbol;\n }\n\n function _postClaimUpdateQueued(\n PoolId poolId,\n ShareClassId scId_,\n bytes32 investor,\n AssetId assetId,\n UserOrder storage userOrder,\n RequestType requestType\n ) private returns (uint128 cancelledAmount) {\n QueuedOrder storage queued = requestType == RequestType.Deposit\n ? queuedDepositRequest[scId_][assetId][investor]\n : queuedRedeemRequest[scId_][assetId][investor];\n\n // Increment pending by queued or cancel everything\n uint128 updatePendingAmount = queued.isCancelling ? userOrder.pending : queued.amount;\n if (queued.isCancelling) {\n cancelledAmount = userOrder.pending + queued.amount;\n userOrder.pending = 0;\n } else {\n userOrder.pending += queued.amount;\n }\n\n if (requestType == RequestType.Deposit) {\n _updatePendingDeposit(\n poolId,\n scId_,\n updatePendingAmount,\n !queued.isCancelling,\n investor,\n assetId,\n userOrder,\n QueuedOrder(false, 0)\n );\n } else {\n _updatePendingRedeem(\n poolId,\n scId_,\n updatePendingAmount,\n !queued.isCancelling,\n investor,\n assetId,\n userOrder,\n QueuedOrder(false, 0)\n );\n }\n\n // Clear queued\n queued.isCancelling = false;\n queued.amount = 0;\n }\n\n /// @notice Updates the amount of a deposit or redeem request.\n ///\n /// @param poolId Identifier of the pool\n /// @param scId_ Identifier of the share class\n /// @param amount Amount which is updated\n /// @param isIncrement Whether the amount is positive (additional request) or negative (cancellation)\n /// @param investor Address of the entity which is depositing\n /// @param assetId Identifier of the asset which the investor either used as deposit or wants to redeem to\n /// @param requestType Flag indicating whether the request is a deposit or redeem request\n /// @return cancelledAmount Pending amount which was cancelled\n function _updatePending(\n PoolId poolId,\n ShareClassId scId_,\n uint128 amount,\n bool isIncrement,\n bytes32 investor,\n AssetId assetId,\n RequestType requestType\n ) private returns (uint128 cancelledAmount) {\n UserOrder storage userOrder = requestType == RequestType.Deposit\n ? depositRequest[scId_][assetId][investor]\n : redeemRequest[scId_][assetId][investor];\n QueuedOrder storage queued = requestType == RequestType.Deposit\n ? queuedDepositRequest[scId_][assetId][investor]\n : queuedRedeemRequest[scId_][assetId][investor];\n\n // We must only update either queued or pending\n if (_updateQueued(poolId, scId_, amount, isIncrement, investor, assetId, userOrder, queued, requestType)) {\n return 0;\n }\n\n cancelledAmount = isIncrement ? 0 : amount;\n // NOTE: If we decrease the pending, we decrease usually by the full amount\n // We keep subtraction of amount over setting to zero on purpose to not limit future higher level logic\n userOrder.pending = isIncrement ? userOrder.pending + amount : userOrder.pending - amount;\n\n userOrder.lastUpdate =\n requestType == RequestType.Deposit ? nowDepositEpoch(scId_, assetId) : nowRedeemEpoch(scId_, assetId);\n\n if (requestType == RequestType.Deposit) {\n _updatePendingDeposit(poolId, scId_, amount, isIncrement, investor, assetId, userOrder, queued);\n } else {\n _updatePendingRedeem(poolId, scId_, amount, isIncrement, investor, assetId, userOrder, queued);\n }\n }\n\n /// @notice Checks whether the pending amount can be updated. If not, it updates the queued amount.\n ///\n /// @param poolId Identifier of the pool\n /// @param scId_ Identifier of the share class\n /// @param amount Amount which is updated\n /// @param isIncrement Whether the amount is positive (additional request) or negative (cancellation)\n /// @param investor Address of the entity which is depositing\n /// @param assetId Identifier of the asset which the investor either used as deposit or wants to redeem to\n /// @param userOrder User order storage for the deposit or redeem request\n /// @param requestType Flag indicating whether the request is a deposit or redeem request\n /// @return skipPendingUpdate Flag indicating whether the pending amount can be updated which is true if the user\n /// does not need to claim\n function _updateQueued(\n PoolId poolId,\n ShareClassId scId_,\n uint128 amount,\n bool isIncrement,\n bytes32 investor,\n AssetId assetId,\n UserOrder storage userOrder,\n QueuedOrder storage queued,\n RequestType requestType\n ) private returns (bool skipPendingUpdate) {\n uint32 lastEpoch =\n requestType == RequestType.Deposit ? epochId[scId_][assetId].deposit : epochId[scId_][assetId].redeem;\n uint32 currentEpoch = lastEpoch + 1;\n\n // Short circuit if user can mutate pending, i.e. last update happened after latest approval or is first update\n if (userOrder.lastUpdate == currentEpoch || userOrder.pending == 0 || lastEpoch == 0) {\n return false;\n }\n\n // Block increasing queued amount if cancelling is already queued\n // NOTE: Can only happen due to race condition as CV blocks requests if cancellation is in progress\n require(!(queued.isCancelling && amount > 0), CancellationQueued());\n\n if (!isIncrement) {\n queued.isCancelling = true;\n } else {\n queued.amount += amount;\n }\n\n if (requestType == RequestType.Deposit) {\n uint128 pendingTotal = pendingDeposit[scId_][assetId];\n emit UpdateDepositRequest(\n poolId,\n scId_,\n assetId,\n currentEpoch,\n investor,\n userOrder.pending,\n pendingTotal,\n queued.amount,\n queued.isCancelling\n );\n } else {\n uint128 pendingTotal = pendingRedeem[scId_][assetId];\n\n emit UpdateRedeemRequest(\n poolId,\n scId_,\n assetId,\n currentEpoch,\n investor,\n userOrder.pending,\n pendingTotal,\n queued.amount,\n queued.isCancelling\n );\n }\n\n return true;\n }\n\n function _updatePendingDeposit(\n PoolId poolId,\n ShareClassId scId_,\n uint128 amount,\n bool isIncrement,\n bytes32 investor,\n AssetId assetId,\n UserOrder storage userOrder,\n QueuedOrder memory queued\n ) private {\n uint128 pendingTotal = pendingDeposit[scId_][assetId];\n pendingTotal = isIncrement ? pendingTotal + amount : pendingTotal - amount;\n pendingDeposit[scId_][assetId] = pendingTotal;\n\n emit UpdateDepositRequest(\n poolId,\n scId_,\n assetId,\n nowDepositEpoch(scId_, assetId),\n investor,\n userOrder.pending,\n pendingTotal,\n queued.amount,\n queued.isCancelling\n );\n }\n\n function _updatePendingRedeem(\n PoolId poolId,\n ShareClassId scId_,\n uint128 amount,\n bool isIncrement,\n bytes32 investor,\n AssetId assetId,\n UserOrder storage userOrder,\n QueuedOrder memory queued\n ) private {\n uint128 pendingTotal = pendingRedeem[scId_][assetId];\n pendingTotal = isIncrement ? pendingTotal + amount : pendingTotal - amount;\n pendingRedeem[scId_][assetId] = pendingTotal;\n\n emit UpdateRedeemRequest(\n poolId,\n scId_,\n assetId,\n nowRedeemEpoch(scId_, assetId),\n investor,\n userOrder.pending,\n pendingTotal,\n queued.amount,\n queued.isCancelling\n );\n }\n}\n" + }, + "src/hub/interfaces/IAccounting.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {AccountId} from \"src/common/types/AccountId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\n\nstruct JournalEntry {\n uint128 value;\n AccountId accountId;\n}\n\ninterface IAccounting {\n /// @notice Emitted when a an entry is done\n event Credit(PoolId indexed poolId, AccountId indexed account, uint128 value);\n event Debit(PoolId indexed poolId, AccountId indexed account, uint128 value);\n\n /// @notice Emitted at the beginning and end of a journal entry\n event StartJournalId(PoolId indexed poolId, uint256 journalId);\n event EndJournalId(PoolId indexed poolId, uint256 journalId);\n\n /// @notice Emitted when a new account is created\n event CreateAccount(PoolId indexed poolId, AccountId indexed account, bool isDebitNormal);\n\n /// @notice Emitted when metadata is set for an account\n event SetAccountMetadata(PoolId indexed poolId, AccountId indexed account, bytes metadata);\n\n /// @notice Dispatched when the pool is already unlocked.\n error AccountingAlreadyUnlocked();\n\n /// @notice Dispatched when the pool is not unlocked to interact with.\n error AccountingLocked();\n\n /// @notice Dispatched when the debit and credit side do not match at the end of a transaction.\n error Unbalanced();\n\n /// @notice Dispatched when trying to create an account that already exists.\n error AccountExists();\n\n /// @notice Dispatched when trying debit or credit an account that doesn't exists.\n error AccountDoesNotExist();\n\n /// @notice Represents an account\n struct Account {\n uint128 totalDebit;\n uint128 totalCredit;\n bool isDebitNormal;\n uint64 lastUpdated;\n bytes metadata;\n }\n\n /// @notice Debits an account. Increase the value of debit-normal accounts, decrease for credit-normal ones.\n /// @param account The account to debit\n /// @param value Amount being debited\n function addDebit(AccountId account, uint128 value) external;\n\n /// @notice Credits an account. Decrease the value of debit-normal accounts, increase for credit-normal ones.\n /// @param account The account to credit\n /// @param value Amount being credited\n function addCredit(AccountId account, uint128 value) external;\n\n /// @notice Apply addDebit and addCredit to each journal entry\n function addJournal(JournalEntry[] memory debits, JournalEntry[] memory credits) external;\n\n /// @notice Unlocks a pool for journal entries\n /// @param poolId The pool to unlock\n function unlock(PoolId poolId) external;\n\n /// @notice Closes the transaction and checks if the entries are balanced.\n function lock() external;\n\n /// @notice Creates an account.\n /// @param poolId The pool the account belongs to\n /// @param account The account to create\n /// @param isDebitNormal Whether the account is debit-normal or credit-normal\n function createAccount(PoolId poolId, AccountId account, bool isDebitNormal) external;\n\n /// @notice Sets metadata associated to an existent account.\n /// @param poolId The pool the account belongs to\n /// @param account The account to set metadata for\n /// @param metadata The metadata to set\n function setAccountMetadata(PoolId poolId, AccountId account, bytes calldata metadata) external;\n\n /// @notice Returns the value of an account\n /// @param poolId The pool the account belongs to\n /// @param account The account to get the value of\n /// @return isPositive Indicates whether value is a positive or negative value\n /// @return value The value of the account\n function accountValue(PoolId poolId, AccountId account) external view returns (bool isPositive, uint128 value);\n\n /// @notice Returns whether an account exists\n /// @param poolId The pool the account belongs to\n /// @param account The account to check\n /// @return True if the account exists, false otherwise\n function exists(PoolId poolId, AccountId account) external view returns (bool);\n}\n" + }, + "src/hub/interfaces/IHoldings.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IERC7726} from \"src/misc/interfaces/IERC7726.sol\";\nimport {D18} from \"src/misc/types/D18.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {AccountId} from \"src/common/types/AccountId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nstruct Holding {\n uint128 assetAmount;\n uint128 assetAmountValue;\n IERC7726 valuation; // Used for existence\n bool isLiability;\n}\n\nstruct HoldingAccount {\n AccountId accountId;\n uint8 kind;\n}\n\ninterface IHoldings {\n /// @notice Emitted when a holding is created\n event Create(\n PoolId indexed,\n ShareClassId indexed scId,\n AssetId indexed assetId,\n IERC7726 valuation,\n bool isLiability,\n HoldingAccount[] accounts\n );\n\n /// @notice Emitted when a holding is increased\n event Increase(\n PoolId indexed,\n ShareClassId indexed scId,\n AssetId indexed assetId,\n D18 pricePoolPerAsset,\n uint128 amount,\n uint128 increasedValue\n );\n\n /// @notice Emitted when a holding is decreased\n event Decrease(\n PoolId indexed,\n ShareClassId indexed scId,\n AssetId indexed assetId,\n D18 pricePoolPerAsset,\n uint128 amount,\n uint128 decreasedValue\n );\n\n /// @notice Emitted when the holding is updated\n event Update(\n PoolId indexed, ShareClassId indexed scId, AssetId indexed assetId, bool isPositive, uint128 diffValue\n );\n\n /// @notice Emitted when a holding valuation is updated\n event UpdateValuation(PoolId indexed, ShareClassId indexed scId, AssetId indexed assetId, IERC7726 valuation);\n\n /// @notice Emitted when an account is for a holding is set\n event SetAccountId(\n PoolId indexed, ShareClassId indexed scId, AssetId indexed assetId, uint8 kind, AccountId accountId\n );\n\n /// @notice Item was not found for a required action\n error HoldingNotFound();\n\n /// @notice Valuation is not valid.\n error WrongValuation();\n\n /// @notice ShareClassId is not valid.\n error WrongShareClassId();\n\n /// @notice AssetId is not valid.\n error WrongAssetId();\n\n /// @notice Creates a new holding in a pool using a valuation\n function create(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n IERC7726 valuation,\n bool isLiability,\n HoldingAccount[] memory accounts\n ) external;\n\n /// @notice Increments the amount of a holding and updates the value for that increment.\n /// @return value The value the holding has increment.\n function increase(PoolId poolId, ShareClassId scId, AssetId assetId, D18 pricePoolPerAsset, uint128 amount)\n external\n returns (uint128 value);\n\n /// @notice Decrements the amount of a holding and updates the value for that decrement.\n /// @return value The value the holding has decrement.\n function decrease(PoolId poolId, ShareClassId scId, AssetId assetId, D18 pricePoolPerAsset, uint128 amount)\n external\n returns (uint128 value);\n\n /// @notice Reset the value of a holding using the current valuation.\n /// @return isPositive Indicates whether the diffValue is positive or negative\n /// @return diffValue The difference in value after the new valuation.\n function update(PoolId poolId, ShareClassId scId, AssetId assetId)\n external\n returns (bool isPositive, uint128 diffValue);\n\n /// @notice Updates the valuation method used for this holding.\n function updateValuation(PoolId poolId, ShareClassId scId, AssetId assetId, IERC7726 valuation) external;\n\n /// @notice Sets an account id for an specific kind\n function setAccountId(PoolId poolId, ShareClassId scId, AssetId assetId, uint8 kind, AccountId accountId)\n external;\n\n /// @notice Returns the value of this holding.\n function value(PoolId poolId, ShareClassId scId, AssetId assetId) external view returns (uint128 value);\n\n /// @notice Returns the amount of this holding.\n function amount(PoolId poolId, ShareClassId scId, AssetId assetId) external view returns (uint128 amount);\n\n /// @notice Returns the valuation method used for this holding.\n function valuation(PoolId poolId, ShareClassId scId, AssetId assetId) external view returns (IERC7726);\n\n /// @notice Returns if the holding is a liability\n function isLiability(PoolId poolId, ShareClassId scId, AssetId assetId) external view returns (bool);\n\n /// @notice Returns an account id for an specific kind\n function accountId(PoolId poolId, ShareClassId scId, AssetId assetId, uint8 kind)\n external\n view\n returns (AccountId);\n\n /// @notice Tells if the holding exists for an asset in a share class\n function exists(PoolId poolId, ShareClassId scId, AssetId assetId) external view returns (bool);\n}\n" + }, + "src/hub/interfaces/IHub.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {D18} from \"src/misc/types/D18.sol\";\nimport {IERC7726} from \"src/misc/interfaces/IERC7726.sol\";\n\nimport {VaultUpdateKind} from \"src/common/libraries/MessageLib.sol\";\nimport {IGateway} from \"src/common/interfaces/IGateway.sol\";\nimport {IPoolMessageSender} from \"src/common/interfaces/IGatewaySenders.sol\";\n\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {AccountId} from \"src/common/types/AccountId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {IShareClassManager} from \"src/hub/interfaces/IShareClassManager.sol\";\nimport {IAccounting, JournalEntry} from \"src/hub/interfaces/IAccounting.sol\";\nimport {IHubRegistry} from \"src/hub/interfaces/IHubRegistry.sol\";\nimport {IHoldings} from \"src/hub/interfaces/IHoldings.sol\";\n\n/// @notice Account types used by Hub\nenum AccountType {\n /// @notice Debit normal account for tracking assets\n Asset,\n /// @notice Credit normal account for tracking equities\n Equity,\n /// @notice Credit normal account for tracking losses\n Loss,\n /// @notice Credit normal account for tracking profits\n Gain,\n /// @notice Debit normal account for tracking expenses\n Expense,\n /// @notice Credit normal account for tracking liabilities\n Liability\n}\n\n/// @notice Interface with all methods available in the system used by actors\ninterface IHub {\n event NotifyPool(uint16 indexed centrifugeId, PoolId indexed poolId);\n event NotifyShareClass(uint16 indexed centrifugeId, PoolId indexed poolId, ShareClassId scId);\n event NotifyShareMetadata(\n uint16 indexed centrifugeId, PoolId indexed poolId, ShareClassId scId, string name, string symbol\n );\n event UpdateShareHook(uint16 indexed centrifugeId, PoolId indexed poolId, ShareClassId scId, bytes32 hook);\n event NotifySharePrice(uint16 indexed centrifugeId, PoolId indexed poolId, ShareClassId scId, D18 poolPerShare);\n event NotifyAssetPrice(\n uint16 indexed centrifugeId, PoolId indexed poolId, ShareClassId scId, AssetId assetId, D18 pricePoolPerAsset\n );\n event UpdateRestriction(uint16 indexed centrifugeId, PoolId indexed poolId, ShareClassId scId, bytes payload);\n event UpdateContract(\n uint16 indexed centrifugeId, PoolId indexed poolId, ShareClassId scId, bytes32 target, bytes payload\n );\n\n /// @notice Emitted when a call to `file()` was performed.\n event File(bytes32 what, address addr);\n\n /// @notice Dispatched when the `what` parameter of `file()` is not supported by the implementation.\n error FileUnrecognizedParam();\n\n /// @notice Dispatched when the pool is already unlocked.\n /// It means when calling to `execute()` inside `execute()`.\n error PoolAlreadyUnlocked();\n\n /// @notice Dispatched when the pool can not be unlocked by the caller\n error NotManager();\n\n /// @notice Dispatched when an invalid centrifuge ID is set in the pool ID.\n error InvalidPoolId();\n\n function gateway() external view returns (IGateway);\n function holdings() external view returns (IHoldings);\n function accounting() external view returns (IAccounting);\n function hubRegistry() external view returns (IHubRegistry);\n function sender() external view returns (IPoolMessageSender);\n function shareClassManager() external view returns (IShareClassManager);\n\n /// @notice Updates a contract parameter.\n /// @param what Name of the parameter to update.\n /// Accepts a `bytes32` representation of 'hubRegistry', 'assetRegistry', 'accounting', 'holdings', 'gateway' and '\n /// sender' as string value.\n function file(bytes32 what, address data) external;\n\n /// @notice Notify a deposit for an investor address located in the chain where the asset belongs\n function notifyDeposit(PoolId poolId, ShareClassId scId, AssetId depositAssetId, bytes32 investor, uint32 maxClaims)\n external\n payable;\n\n /// @notice Notify a redemption for an investor address located in the chain where the asset belongs\n function notifyRedeem(PoolId poolId, ShareClassId scId, AssetId payoutAssetId, bytes32 investor, uint32 maxClaims)\n external\n payable;\n\n /// @notice Notify to a CV instance that a new pool is available\n /// @param centrifugeId Chain where CV instance lives\n function notifyPool(PoolId poolId, uint16 centrifugeId) external payable;\n\n /// @notice Notify to a CV instance that a new share class is available\n /// @param centrifugeId Chain where CV instance lives\n /// @param hook The hook address of the share class\n function notifyShareClass(PoolId poolId, ShareClassId scId, uint16 centrifugeId, bytes32 hook) external payable;\n\n /// @notice Notify to a CV instance that share metadata has updated\n function notifyShareMetadata(PoolId poolId, ShareClassId scId, uint16 centrifugeId) external payable;\n\n /// @notice Update on a CV instance the hook of a share token\n function updateShareHook(PoolId poolId, ShareClassId scId, uint16 centrifugeId, bytes32 hook) external payable;\n\n /// @notice Notify to a CV instance the latest available price in POOL_UNIT / SHARE_UNIT\n /// @dev The receiving centrifugeId is derived from the provided assetId\n /// @param centrifugeId Chain to where the share price is notified\n /// @param scId Identifier of the share class\n function notifySharePrice(PoolId poolId, ShareClassId scId, uint16 centrifugeId) external payable;\n\n /// @notice Notify to a CV instance the latest available price in POOL_UNIT / ASSET_UNIT\n /// @dev The receiving centrifugeId is derived from the provided assetId\n /// @param scId Identifier of the share class\n /// @param assetId Identifier of the asset\n function notifyAssetPrice(PoolId poolId, ShareClassId scId, AssetId assetId) external payable;\n\n /// @notice Attach custom data to a pool\n function setPoolMetadata(PoolId poolId, bytes calldata metadata) external payable;\n\n /// @notice Update name & symbol of share class\n function updateShareClassMetadata(PoolId poolId, ShareClassId scId, string calldata name, string calldata symbol)\n external\n payable;\n\n /// @notice Allow/disallow an account to interact as pool manager\n function updateManager(PoolId poolId, address who, bool canManage) external payable;\n\n /// @notice Add a new share class to the pool\n function addShareClass(PoolId poolId, string calldata name, string calldata symbol, bytes32 salt)\n external\n payable\n returns (ShareClassId scId);\n\n /// @notice Approves an asset amount of all deposit requests for the given triplet of pool id, share class id and\n /// deposit asset id.\n /// @param scId Identifier of the share class\n /// @param depositAssetId Identifier of the asset locked for the deposit request\n /// @param nowDepositEpochId The epoch for which deposits will be approved.\n /// @param approvedAssetAmount Ampunt of assets that will be approved\n function approveDeposits(\n PoolId poolId,\n ShareClassId scId,\n AssetId depositAssetId,\n uint32 nowDepositEpochId,\n uint128 approvedAssetAmount\n ) external payable returns (uint128 pendingAssetAmount, uint128 approvedPoolAmount);\n\n /// @notice Approves a percentage of all redemption requests for the given triplet of pool id, share class id and\n /// deposit asset id.\n /// @param scId Identifier of the share class\n /// @param payoutAssetId Identifier of the asset for which all requests want to exchange their share class tokens\n /// @param nowRedeemEpochId The epoch for which redemptions will be approved.\n /// @param approvedShareAmount Amount of shares that will be approved\n function approveRedeems(\n PoolId poolId,\n ShareClassId scId,\n AssetId payoutAssetId,\n uint32 nowRedeemEpochId,\n uint128 approvedShareAmount\n ) external payable returns (uint128 pendingShareAmount);\n\n /// @notice Emits new shares for the given identifier based on the provided NAV per share.\n /// @param depositAssetId Identifier of the deposit asset for which shares should be issued\n /// @param nowIssueEpochId The epoch for which shares will be issued.\n /// @param navPoolPerShare Total value of assets of the share class per share\n function issueShares(\n PoolId poolId,\n ShareClassId id,\n AssetId depositAssetId,\n uint32 nowIssueEpochId,\n D18 navPoolPerShare\n ) external payable returns (uint128 issuedShareAmount, uint128 depositAssetAmount, uint128 depositPoolAmount);\n\n /// @notice Take back shares for the given identifier based on the provided NAV per share.\n /// deposit asset id.\n /// @param payoutAssetId Identifier of the asset for which all requests want to exchange their share class tokens\n /// @param nowRevokeEpochId The epoch for which shares will be issued.\n /// @param navPoolPerShare Total value of assets of the share class per share\n function revokeShares(\n PoolId poolId,\n ShareClassId scId,\n AssetId payoutAssetId,\n uint32 nowRevokeEpochId,\n D18 navPoolPerShare\n ) external payable returns (uint128 revokedShareAmount, uint128 payoutAssetAmount, uint128 payoutPoolAmount);\n\n /// @notice Tells the BalanceSheet to issue/revoke shares.\n function triggerIssueShares(uint16 centrifugeId, PoolId poolId, ShareClassId scId, address who, uint128 shares)\n external\n payable;\n\n /// @notice Tell the BalanceSheet to send a message back with the queued issued/revoked shares.\n function triggerSubmitQueuedShares(uint16 centrifugeId, PoolId poolId, ShareClassId scId) external payable;\n\n /// @notice Tell the BalanceSheet to send a message back with the queued deposits/withdrawals.\n /// @param assetId Identifier of the asset which has queued deposits/withdrawals\n function triggerSubmitQueuedAssets(PoolId poolId, ShareClassId scId, AssetId assetId) external payable;\n\n /// @notice Tell the BalanceSheet to enable or disable the shares queue.\n function setQueue(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bool enabled) external payable;\n\n /// @notice Update remotely a restriction.\n /// @param centrifugeId Chain where CV instance lives.\n /// @param payload content of the restriction update to execute.\n function updateRestriction(PoolId poolId, ShareClassId scId, uint16 centrifugeId, bytes calldata payload)\n external\n payable;\n\n /// @notice Update remotely an existing vault.\n /// @param centrifugeId Chain where CV instance lives.\n /// @param target contract where to execute in CV. Check IUpdateContract interface.\n /// @param payload content of the update to execute.\n function updateContract(\n PoolId poolId,\n ShareClassId scId,\n uint16 centrifugeId,\n bytes32 target,\n bytes calldata payload\n ) external payable;\n\n /// @notice Update the price per share of a share class\n /// @param scId The share class identifier\n /// @param pricePoolPerShare The new price per share\n function updatePricePerShare(PoolId poolId, ShareClassId scId, D18 pricePoolPerShare) external payable;\n\n /// @notice Create a new holding associated to the asset in a share class.\n /// It will register the different accounts used for holdings.\n /// The accounts have to be created beforehand.\n /// The same account can be used for different kinds.\n /// e.g.: The equity, gain, and loss account can be the same account.\n /// They can also be shared across assets.\n /// e.g.: All assets can use the same equity account.\n /// @param valuation Used to transform between payment assets and pool currency\n /// @param assetAccount Used to track the asset value\n /// @param equityAccount Used to track the equity value\n /// @param gainAccount Used to track the gain value\n /// @param lossAccount Used to track the loss value\n function createHolding(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n IERC7726 valuation,\n AccountId assetAccount,\n AccountId equityAccount,\n AccountId gainAccount,\n AccountId lossAccount\n ) external payable;\n\n /// @notice Create a new liablity associated to the asset in a share class.\n /// It will register the different accounts used for holdings.\n /// The accounts have to be created beforehand.\n /// @param valuation Used to transform between the holding asset and pool currency\n /// @param expenseAccount Used to track the expense value\n /// @param liabilityAccount Used to track the liability value\n function createLiability(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n IERC7726 valuation,\n AccountId expenseAccount,\n AccountId liabilityAccount\n ) external payable;\n\n /// @notice Updates the pool currency value of this holding based of the associated valuation.\n function updateHoldingValue(PoolId poolId, ShareClassId scId, AssetId assetId) external payable;\n\n /// @notice Updates the valuation used by a holding\n /// @param valuation Used to transform between the holding asset and pool currency\n function updateHoldingValuation(PoolId poolId, ShareClassId scId, AssetId assetId, IERC7726 valuation)\n external\n payable;\n\n /// @notice Set an account of a holding\n function setHoldingAccountId(PoolId poolId, ShareClassId scId, AssetId assetId, uint8 kind, AccountId accountId)\n external\n payable;\n\n /// @notice Creates an account\n /// @param accountId Then new AccountId used\n /// @param isDebitNormal Determines if the account should be used as debit-normal or credit-normal\n function createAccount(PoolId poolId, AccountId accountId, bool isDebitNormal) external payable;\n\n /// @notice Attach custom data to an account\n function setAccountMetadata(PoolId poolId, AccountId account, bytes calldata metadata) external payable;\n\n /// @notice Perform an accounting entries update.\n function updateJournal(PoolId poolId, JournalEntry[] memory debits, JournalEntry[] memory credits) external;\n}\n" + }, + "src/hub/interfaces/IHubRegistry.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IERC6909Decimals} from \"src/misc/interfaces/IERC6909.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {IShareClassManager} from \"src/hub/interfaces/IShareClassManager.sol\";\n\ninterface IHubRegistry is IERC6909Decimals {\n event NewAsset(AssetId indexed assetId, uint8 decimals);\n event NewPool(PoolId poolId, address indexed manager, AssetId indexed currency);\n event UpdateManager(PoolId indexed poolId, address indexed manager, bool canManage);\n event SetMetadata(PoolId indexed poolId, bytes metadata);\n event UpdateDependency(bytes32 indexed what, address dependency);\n event UpdateCurrency(PoolId indexed poolId, AssetId currency);\n\n error NonExistingPool(PoolId id);\n error AssetAlreadyRegistered();\n error PoolAlreadyRegistered();\n error EmptyAccount();\n error EmptyCurrency();\n error EmptyShareClassManager();\n error AssetNotFound();\n\n /// @notice Register a new asset.\n function registerAsset(AssetId assetId, uint8 decimals_) external;\n\n /// @notice Register a new pool.\n function registerPool(PoolId poolId, address manager, AssetId currency) external;\n\n /// @notice allow/disallow an address as a manager for the pool\n function updateManager(PoolId poolId, address newManager, bool canManage) external;\n\n /// @notice sets metadata for this pool\n function setMetadata(PoolId poolId, bytes calldata metadata) external;\n\n /// @notice updates a dependency of the system\n function updateDependency(bytes32 what, address dependency) external;\n\n /// @notice updates the currency of the pool\n function updateCurrency(PoolId poolId, AssetId currency) external;\n\n /// @notice returns the metadata attached to the pool, if any.\n function metadata(PoolId poolId) external view returns (bytes memory);\n\n /// @notice returns the currency of the pool\n function currency(PoolId poolId) external view returns (AssetId);\n\n /// @notice returns the dependency used in the system\n function dependency(bytes32 what) external view returns (address);\n\n /// @notice returns whether the account is a manager\n function manager(PoolId poolId, address who) external view returns (bool);\n\n /// @notice compute a pool ID given an ID postfix\n function poolId(uint16 centrifugeId, uint48 postfix) external view returns (PoolId poolId);\n\n /// @notice returns the decimals for an asset\n function decimals(AssetId assetId) external view returns (uint8);\n\n /// @notice returns the decimals for a pool\n function decimals(PoolId poolId) external view returns (uint8);\n\n /// @notice checks the existence of a pool\n function exists(PoolId poolId) external view returns (bool);\n\n /// @notice checks the existence of an asset\n function isRegistered(AssetId assetId) external view returns (bool);\n}\n" + }, + "src/hub/interfaces/IShareClassManager.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {D18} from \"src/misc/types/D18.sol\";\nimport {IERC7726} from \"src/misc/interfaces/IERC7726.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nstruct EpochRedeemAmounts {\n /// @dev Amount of shares pending to be redeemed at time of epoch\n uint128 pendingShareAmount;\n /// @dev Total approved amount of redeemed share class tokens\n uint128 approvedShareAmount;\n /// @dev Total asset amount of revoked share class tokens\n uint128 payoutAssetAmount;\n /// @dev The amount of pool currency per unit of asset at time of approval\n D18 pricePoolPerAsset;\n /// @dev The amount of pool currency per unit of share at time of revocation\n D18 navPoolPerShare;\n /// @dev block timestamp when shares of epoch were revoked\n uint64 revokedAt;\n}\n\nstruct EpochInvestAmounts {\n /// @dev Total pending asset amount of deposit asset at time of epoch\n uint128 pendingAssetAmount;\n /// @dev Total approved asset amount of deposit asset\n uint128 approvedAssetAmount;\n /// @dev Total approved pool amount of deposit asset\n uint128 approvedPoolAmount;\n /// @dev The amount of pool currency per unit of asset at time of approval\n D18 pricePoolPerAsset;\n /// @dev The amount of pool currency per unit of share at time of issuance\n D18 navPoolPerShare;\n /// @dev block timestamp when shares of epoch were issued\n uint64 issuedAt;\n}\n\nstruct UserOrder {\n /// @dev Pending amount in deposit asset denomination\n uint128 pending;\n /// @dev Index of epoch in which last order was made\n uint32 lastUpdate;\n}\n\nstruct ShareClassMetadata {\n /// @dev The name of the share class token\n string name;\n /// @dev The symbol of the share class token\n string symbol;\n /// @dev The salt of the share class token\n bytes32 salt;\n}\n\nstruct ShareClassMetrics {\n /// @dev Total number of shares\n uint128 totalIssuance;\n /// @dev The latest net asset value per share class token\n D18 navPerShare;\n}\n\nstruct QueuedOrder {\n /// @dev Whether the user requested a cancellation which is now queued\n bool isCancelling;\n /// @dev The queued increased request amount\n uint128 amount;\n}\n\nenum RequestType {\n /// @dev Whether the request is a deposit one\n Deposit,\n /// @dev Whether the request is a redeem one\n Redeem\n}\n\nstruct EpochId {\n uint32 deposit;\n uint32 redeem;\n uint32 issue;\n uint32 revoke;\n}\n\ninterface IShareClassManager {\n /// Events\n event AddShareClass(\n PoolId indexed poolId, ShareClassId indexed scId, uint32 indexed index, string name, string symbol, bytes32 salt\n );\n event UpdateMetadata(PoolId indexed poolId, ShareClassId indexed scId, string name, string symbol);\n event ApproveDeposits(\n PoolId indexed poolId,\n ShareClassId indexed scId,\n AssetId indexed depositAssetId,\n uint32 epoch,\n uint128 approvedPoolAmount,\n uint128 approvedAssetAmount,\n uint128 pendingAssetAmount\n );\n event ApproveRedeems(\n PoolId indexed poolId,\n ShareClassId indexed scId,\n AssetId indexed payoutAssetId,\n uint32 epoch,\n uint128 approvedShareAmount,\n uint128 pendingShareAmount\n );\n event IssueShares(\n PoolId indexed poolId,\n ShareClassId indexed scId,\n AssetId indexed depositAssetId,\n uint32 epoch,\n D18 navPoolPerShare,\n D18 navAssetPerShare,\n uint128 issuedShareAmount\n );\n event RemoteIssueShares(PoolId indexed poolId, ShareClassId indexed scId, uint128 issuedShareAmount);\n event RevokeShares(\n PoolId indexed poolId,\n ShareClassId indexed scId,\n AssetId indexed payoutAssetId,\n uint32 epoch,\n D18 navPoolPerShare,\n D18 navAssetPerShare,\n uint128 revokedShareAmount,\n uint128 revokedAssetAmount,\n uint128 revokedPoolAmount\n );\n event RemoteRevokeShares(PoolId indexed poolId, ShareClassId indexed scId, uint128 revokedAssetAmount);\n event ClaimDeposit(\n PoolId indexed poolId,\n ShareClassId indexed scId,\n uint32 epoch,\n bytes32 investor,\n AssetId indexed depositAssetId,\n uint128 paymentAssetAmount,\n uint128 pendingAssetAmount,\n uint128 claimedShareAmount,\n uint64 issuedAt\n );\n event ClaimRedeem(\n PoolId indexed poolId,\n ShareClassId indexed scId,\n uint32 epoch,\n bytes32 investor,\n AssetId indexed payoutAssetId,\n uint128 paymentShareAmount,\n uint128 pendingShareAmount,\n uint128 claimedAssetAmount,\n uint64 revokedAt\n );\n event AddShareClass(PoolId indexed poolId, ShareClassId indexed scId, uint32 indexed index);\n event UpdateShareClass(PoolId indexed poolId, ShareClassId indexed scId, D18 navPoolPerShare);\n event UpdateDepositRequest(\n PoolId indexed poolId,\n ShareClassId indexed scId,\n AssetId indexed depositAssetId,\n uint32 epoch,\n bytes32 investor,\n uint128 pendingUserAssetAmount,\n uint128 pendingTotalAssetAmount,\n uint128 queuedUserAssetAmount,\n bool pendingCancellation\n );\n event UpdateRedeemRequest(\n PoolId indexed poolId,\n ShareClassId indexed scId,\n AssetId indexed payoutAssetId,\n uint32 epoch,\n bytes32 investor,\n uint128 pendingUserShareAmount,\n uint128 pendingTotalShareAmount,\n uint128 queuedUserShareAmount,\n bool pendingCancellation\n );\n\n /// Errors\n error EpochNotInSequence(uint32 providedEpoch, uint32 nowEpoch);\n error NoOrderFound();\n error InsufficientPending();\n error ApprovalRequired();\n error IssuanceRequired();\n error AlreadyIssued();\n error RevocationRequired();\n error ZeroApprovalAmount();\n error InvalidMetadataSize();\n error InvalidMetadataName();\n error InvalidMetadataSymbol();\n error InvalidSalt();\n error AlreadyUsedSalt();\n error RevokeMoreThanIssued();\n error PoolMissing();\n error ShareClassNotFound();\n error EpochNotFound();\n error DecreaseMoreThanIssued();\n error CancellationQueued();\n\n /// Functions\n\n /// @notice Creates or updates a request to deposit (exchange) an asset amount for share class tokens.\n ///\n /// @param poolId Identifier of the pool\n /// @param scId Identifier of the share class\n /// @param amount Asset token amount which is deposited\n /// @param investor Centrifuge Vault address of the entity which is depositing\n /// @param depositAssetId Identifier of the asset which the investor used for their deposit request\n function requestDeposit(PoolId poolId, ShareClassId scId, uint128 amount, bytes32 investor, AssetId depositAssetId)\n external;\n\n /// @notice Cancels a pending deposit request.\n ///\n /// @param poolId Identifier of the pool\n /// @param scId Identifier of the share class\n /// @param investor Centrifuge Vault address of the entity which is cancelling\n /// @param depositAssetId Identifier of the asset which the investor used for their deposit request\n /// @return cancelledAssetAmount The deposit amount which was previously pending and is now cancelled. This amount\n /// was not potentially (partially) swapped to the pool amount in case the deposit asset cannot be exchanged 1:1\n /// into the pool token\n function cancelDepositRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId depositAssetId)\n external\n returns (uint128 cancelledAssetAmount);\n\n /// @notice Creates or updates a request to redeem (exchange) share class tokens for some asset.\n ///\n /// @param poolId Identifier of the pool\n /// @param scId Identifier of the share class\n /// @param amount Share class token amount which should be redeemed\n /// @param investor Centrifuge Vault address of the entity which is redeeming\n /// @param payoutAssetId Identifier of the asset which the investor eventually receives back for their redeemed\n /// share class tokens\n function requestRedeem(PoolId poolId, ShareClassId scId, uint128 amount, bytes32 investor, AssetId payoutAssetId)\n external;\n\n /// @notice Cancels a pending redeem request.\n ///\n /// @param poolId Identifier of the pool\n /// @param scId Identifier of the share class\n /// @param investor Centrifuge Vault address of the entity which is cancelling\n /// @param payoutAssetId Identifier of the asset which the investor eventually receives back for their redeemed\n /// share class tokens\n /// @return cancelledShareAmount The redeem amount which was previously pending and is now cancelled\n function cancelRedeemRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId payoutAssetId)\n external\n returns (uint128 cancelledShareAmount);\n\n /// @notice Approves an asset amount of all deposit requests for the given triplet of pool id, share class id and\n /// deposit asset id.\n /// @dev nowDepositEpochId MUST be called sequentially.\n ///\n /// @param poolId Identifier of the pool\n /// @param scId Identifier of the share class\n /// @param depositAssetId Identifier of the asset locked for the deposit request\n /// @param nowDepositEpochId The epoch for which shares will be approved.\n /// @param approvedAssetAmount Amount of assets that will be approved for deposit\n /// @param pricePoolPerAsset Amount of pool unit one gets for a unit of asset\n /// @return pendingAssetAmount Amount of assets still pending for deposit\n /// @return approvedPoolAmount Amount of pool units approved for deposit\n function approveDeposits(\n PoolId poolId,\n ShareClassId scId,\n AssetId depositAssetId,\n uint32 nowDepositEpochId,\n uint128 approvedAssetAmount,\n D18 pricePoolPerAsset\n ) external returns (uint128 pendingAssetAmount, uint128 approvedPoolAmount);\n\n /// @notice Approves a share class token amount of all redeem requests for the given triplet of pool id, share class\n /// id and payout asset id.\n /// @dev nowRedeemEpochId MUST be called sequentially.\n ///\n /// @param poolId Identifier of the pool\n /// @param scId Identifier of the share class\n /// @param payoutAssetId Identifier of the asset for which all requests want to exchange their share class tokens\n /// for\n /// @param nowRedeemEpochId The epoch for which shares will be approved.\n /// @param approvedShareAmount Amount of shares that will be approved for redemption\n /// @param pricePoolPerAsset Amount of pool unit one gets for a unit of asset\n /// @return pendingShareAmount Sum of redemption request amounts in share class token amount which was not approved\n function approveRedeems(\n PoolId poolId,\n ShareClassId scId,\n AssetId payoutAssetId,\n uint32 nowRedeemEpochId,\n uint128 approvedShareAmount,\n D18 pricePoolPerAsset\n ) external returns (uint128 pendingShareAmount);\n\n /// @notice Emits new shares for the given identifier based on the provided NAV per share.\n /// @dev nowIssueEpochId MUST be called sequentially.\n ///\n /// @param poolId Identifier of the pool\n /// @param scId Identifier of the share class\n /// @param depositAssetId Identifier of the deposit asset for which shares should be issued\n /// @param nowIssueEpochId The epoch for which shares will be issued.\n /// @param navPoolPerShare The nav per share value of the share class (in the pool currency denomination. Conversion\n /// to asset price is done onchain based on the valuation of the asset at approval)\n /// @return issuedShareAmount Amount of shares that have been issued\n function issueShares(\n PoolId poolId,\n ShareClassId scId,\n AssetId depositAssetId,\n uint32 nowIssueEpochId,\n D18 navPoolPerShare\n ) external returns (uint128 issuedShareAmount, uint128 depositAssetAmount, uint128 depositPoolAmount);\n\n /// @notice Take back shares for the given identifier based on the provided NAV per share.\n /// @dev nowRevokeEpochId MUST be called sequentially.\n ///\n /// @param poolId Identifier of the pool\n /// @param scId Identifier of the share class\n /// @param payoutAssetId Identifier of the payout asset\n /// @param nowRevokeEpochId The epoch for which shares will be revoked.\n /// @param navPoolPerShare The nav per share value of the share class (in the pool currency denomination. Conversion\n /// to asset price is done onchain based on the valuation of the asset at approval)\n /// @return revokedShareAmount Amount of shares that have been revoked\n /// @return payoutAssetAmount Converted amount of payout asset based on number of revoked shares\n /// @return payoutPoolAmount Converted amount of pool currency based on number of revoked shares\n function revokeShares(\n PoolId poolId,\n ShareClassId scId,\n AssetId payoutAssetId,\n uint32 nowRevokeEpochId,\n D18 navPoolPerShare\n ) external returns (uint128 revokedShareAmount, uint128 payoutAssetAmount, uint128 payoutPoolAmount);\n\n /// @notice Collects shares for an investor after their deposit request was (partially) approved and new shares were\n /// issued.\n ///\n /// @param poolId Identifier of the pool\n /// @param scId Identifier of the share class\n /// @param investor Centrifuge Vault address of the recipient of the claimed share class tokens\n /// @param depositAssetId Identifier of the asset which the investor used for their deposit request\n /// @return payoutShareAmount Amount of shares which the investor receives\n /// @return paymentAssetAmount Amount of deposit asset which was taken as payment\n /// @return cancelledAssetAmount Amount of deposit asset which was cancelled due to being queued\n /// @return canClaimAgain Whether another call to claimRedeem is needed until investor has fully claimed investments\n function claimDeposit(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId depositAssetId)\n external\n returns (\n uint128 payoutShareAmount,\n uint128 paymentAssetAmount,\n uint128 cancelledAssetAmount,\n bool canClaimAgain\n );\n\n /// @notice Collects an asset amount for an investor after their redeem request was (partially) approved and shares\n /// were revoked.\n ///\n /// @param poolId Identifier of the pool\n /// @param scId Identifier of the share class\n /// @param investor Centrifuge Vault address of the recipient of the claimed asset amount\n /// @param payoutAssetId Identifier of the asset which the investor requested to receive back for their redeemed\n /// shares\n /// @return payoutAssetAmount Amount of payout amount which the investor receives\n /// @return paymentShareAmount Amount of shares which the investor redeemed\n /// @return cancelledShareAmount Amount of shares which were cancelled due to being queued\n /// @return canClaimAgain Whether another call to claimRedeem is needed until investor has fully claimed redemptions\n function claimRedeem(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId payoutAssetId)\n external\n returns (\n uint128 payoutAssetAmount,\n uint128 paymentShareAmount,\n uint128 cancelledShareAmount,\n bool canClaimAgain\n );\n\n /// @notice Increases the share class issuance\n ///\n /// @param poolId Identifier of the pool\n /// @param scId Identifier of the share class\n /// @param amount The amount to increase the share class issuance by\n function increaseShareClassIssuance(PoolId poolId, ShareClassId scId, uint128 amount) external;\n\n /// @notice Decreases the share class issuance\n ///\n /// @param poolId Identifier of the pool\n /// @param scId Identifier of the share class\n /// @param amount The amount to decrease the share class issuance by\n function decreaseShareClassIssuance(PoolId poolId, ShareClassId scId, uint128 amount) external;\n\n /// @notice Adds a new share class to the given pool.\n ///\n /// @param poolId Identifier of the pool\n /// @param name The name of the share class\n /// @param symbol The symbol of the share class\n /// @param salt The salt used for deploying the share class tokens\n /// @return scId Identifier of the newly added share class\n function addShareClass(PoolId poolId, string calldata name, string calldata symbol, bytes32 salt)\n external\n returns (ShareClassId scId);\n\n /// @notice Updates the price pool unit per share unit of a share class\n ///\n /// @param poolId Identifier of the pool\n /// @param scId Identifier of the share class\n /// @param pricePoolPerShare The price per share of the share class (in the pool currency denomination)\n function updatePricePerShare(PoolId poolId, ShareClassId scId, D18 pricePoolPerShare) external;\n\n /// @notice Updates the metadata of a share class.\n ///\n /// @param poolId Identifier of the pool\n /// @param scId Identifier of the share class\n /// @param name The name of the share class\n /// @param symbol The symbol of the share class\n function updateMetadata(PoolId poolId, ShareClassId scId, string calldata name, string calldata symbol) external;\n\n /// @notice Returns the number of share classes for the given pool\n ///\n /// @param poolId Identifier of the pool in question\n /// @return count Number of share classes for the given pool\n function shareClassCount(PoolId poolId) external view returns (uint32 count);\n\n /// @notice Checks the existence of a share class.\n ///\n /// @param poolId Identifier of the pool\n /// @param scId Identifier of the share class\n function exists(PoolId poolId, ShareClassId scId) external view returns (bool);\n\n /// @notice Returns the current ongoing epoch id for deposits\n ///\n /// @param scId Identifier of the share class\n /// @param depositAssetId AssetId of the payment asset\n function nowDepositEpoch(ShareClassId scId, AssetId depositAssetId) external view returns (uint32);\n\n /// @notice Returns the epoch for which will be issued next\n ///\n /// @param scId Identifier of the share class\n /// @param depositAssetId AssetId of the payment asset\n function nowIssueEpoch(ShareClassId scId, AssetId depositAssetId) external view returns (uint32);\n\n /// @notice Returns the current ongoing epoch id for deposits\n ///\n /// @param scId Identifier of the share class\n /// @param payoutAssetId AssetId of the payment asset\n function nowRedeemEpoch(ShareClassId scId, AssetId payoutAssetId) external view returns (uint32);\n\n /// @notice Returns the epoch for which will be revoked next\n ///\n /// @param scId Identifier of the share class\n /// @param depositAssetId AssetId of the payment asset\n function nowRevokeEpoch(ShareClassId scId, AssetId depositAssetId) external view returns (uint32);\n\n /// @notice Returns an upper bound for possible calls to `function claimDeposit(..)`\n ///\n /// @param scId Identifier of the share class\n /// @param investor Recipient of the share class tokens\n /// @param depositAssetId AssetId of the payment asset\n function maxDepositClaims(ShareClassId scId, bytes32 investor, AssetId depositAssetId)\n external\n view\n returns (uint32 maxClaims);\n\n /// @notice Returns an upper bound for possible calls to `function claimRedeem(..)`\n ///\n /// @param scId Identifier of the share class\n /// @param investor Recipient of the payout assets\n /// @param payoutAssetId AssetId of the payout asset\n function maxRedeemClaims(ShareClassId scId, bytes32 investor, AssetId payoutAssetId)\n external\n view\n returns (uint32 maxClaims);\n\n /// @notice Exposes relevant metrics for a share class\n ///\n /// @return totalIssuance The total number of shares known to the CP side\n /// @return pricePoolPerShare The amount of pool units per unit share\n function metrics(ShareClassId scId) external view returns (uint128 totalIssuance, D18 pricePoolPerShare);\n\n /// @notice Determines the next share class id for the given pool.\n ///\n /// @param poolId Identifier of the pool\n /// @return scId Identifier of the next share class\n function previewNextShareClassId(PoolId poolId) external view returns (ShareClassId scId);\n\n /// @notice Determines the share class id for the given pool and index.\n ///\n /// @param poolId Identifier of the pool\n /// @param index The pool-internal index of the share class id\n /// @return scId Identifier of the underlying share class\n function previewShareClassId(PoolId poolId, uint32 index) external pure returns (ShareClassId scId);\n\n /// @notice returns The metadata of the share class.\n ///\n /// @param scId Identifier of the share class\n /// @return name The registered name of the share class token\n /// @return symbol The registered symbol of the share class token\n /// @return salt The registered salt of the share class token, used for deterministic deployments\n function metadata(ShareClassId scId) external returns (string memory name, string memory symbol, bytes32 salt);\n}\n" + }, + "src/misc/Auth.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IAuth} from \"src/misc/interfaces/IAuth.sol\";\n\n/// @title Auth\n/// @notice Simple authentication pattern\n/// @author Based on code from https://github.com/makerdao/dss\nabstract contract Auth is IAuth {\n /// @inheritdoc IAuth\n mapping(address => uint256) public wards;\n\n constructor(address initialWard) {\n wards[initialWard] = 1;\n emit Rely(initialWard);\n }\n\n /// @dev Check if the msg.sender has permissions\n modifier auth() {\n require(wards[msg.sender] == 1, NotAuthorized());\n _;\n }\n\n /// @inheritdoc IAuth\n function rely(address user) public auth {\n wards[user] = 1;\n emit Rely(user);\n }\n\n /// @inheritdoc IAuth\n function deny(address user) public auth {\n wards[user] = 0;\n emit Deny(user);\n }\n}\n" + }, + "src/misc/BaseValuation.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IBaseValuation} from \"src/misc/interfaces/IBaseValuation.sol\";\nimport {IERC6909Decimals} from \"src/misc/interfaces/IERC6909.sol\";\n\nimport {Auth} from \"src/misc/Auth.sol\";\n\nabstract contract BaseValuation is Auth, IBaseValuation {\n /// @notice ERC6909 dependency.\n IERC6909Decimals public erc6909;\n\n constructor(IERC6909Decimals erc6909_, address deployer) Auth(deployer) {\n erc6909 = erc6909_;\n }\n\n /// @inheritdoc IBaseValuation\n function file(bytes32 what, address data) external auth {\n if (what == \"erc6909\") erc6909 = IERC6909Decimals(data);\n else revert FileUnrecognizedParam();\n\n emit File(what, data);\n }\n\n /// @notice Obtain the correct decimals given an asset address\n function _getDecimals(address asset) internal view returns (uint8) {\n return erc6909.decimals(uint160(asset));\n }\n}\n" + }, + "src/misc/ERC20.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {EIP712Lib} from \"src/misc/libraries/EIP712Lib.sol\";\nimport {SignatureLib} from \"src/misc/libraries/SignatureLib.sol\";\n\nimport {IERC20, IERC20Metadata, IERC20Permit} from \"src/misc/interfaces/IERC20.sol\";\n\n/// @title ERC20\n/// @notice Standard ERC-20 implementation, with mint/burn functionality and permit logic.\n/// @author Modified from https://github.com/makerdao/xdomain-dss/blob/master/src/Dai.sol\ncontract ERC20 is Auth, IERC20Metadata, IERC20Permit {\n error FileUnrecognizedParam();\n\n /// @inheritdoc IERC20Metadata\n string public name;\n /// @inheritdoc IERC20Metadata\n string public symbol;\n /// @inheritdoc IERC20Metadata\n uint8 public immutable decimals;\n /// @inheritdoc IERC20\n uint256 public totalSupply;\n\n mapping(address => uint256) private balances;\n\n /// @inheritdoc IERC20\n mapping(address => mapping(address => uint256)) public allowance;\n /// @inheritdoc IERC20Permit\n mapping(address => uint256) public nonces;\n\n // --- EIP712 ---\n bytes32 private immutable nameHash;\n bytes32 private immutable versionHash;\n uint256 public immutable deploymentChainId;\n bytes32 private immutable _DOMAIN_SEPARATOR;\n bytes32 public constant PERMIT_TYPEHASH =\n keccak256(\"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\");\n\n // --- Events ---\n event File(bytes32 indexed what, string data);\n\n constructor(uint8 decimals_) Auth(msg.sender) {\n decimals = decimals_;\n\n nameHash = keccak256(bytes(\"Centrifuge\"));\n versionHash = keccak256(bytes(\"1\"));\n deploymentChainId = block.chainid;\n _DOMAIN_SEPARATOR = EIP712Lib.calculateDomainSeparator(nameHash, versionHash);\n }\n\n function _balanceOf(address user) internal view virtual returns (uint256) {\n return balances[user];\n }\n\n /// @inheritdoc IERC20\n function balanceOf(address user) public view virtual returns (uint256) {\n return _balanceOf(user);\n }\n\n function _setBalance(address user, uint256 value) internal virtual {\n balances[user] = value;\n }\n\n /// @inheritdoc IERC20Permit\n function DOMAIN_SEPARATOR() public view returns (bytes32) {\n return block.chainid == deploymentChainId\n ? _DOMAIN_SEPARATOR\n : EIP712Lib.calculateDomainSeparator(nameHash, versionHash);\n }\n\n // --- Administration ---\n function file(bytes32 what, string memory data) public virtual auth {\n if (what == \"name\") name = data;\n else if (what == \"symbol\") symbol = data;\n else revert FileUnrecognizedParam();\n emit File(what, data);\n }\n\n // --- ERC20 Mutations ---\n /// @inheritdoc IERC20\n function transfer(address to, uint256 value) public virtual returns (bool) {\n require(to != address(0) && to != address(this), InvalidAddress());\n uint256 balance = balanceOf(msg.sender);\n require(balance >= value, InsufficientBalance());\n\n unchecked {\n _setBalance(msg.sender, balance - value);\n // note: we don't need an overflow check here b/c sum of all balances == totalSupply\n _setBalance(to, _balanceOf(to) + value);\n }\n\n emit Transfer(msg.sender, to, value);\n\n return true;\n }\n\n /// @inheritdoc IERC20\n function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {\n return _transferFrom(msg.sender, from, to, value);\n }\n\n function _transferFrom(address sender, address from, address to, uint256 value) internal virtual returns (bool) {\n require(to != address(0) && to != address(this), InvalidAddress());\n uint256 balance = balanceOf(from);\n require(balance >= value, InsufficientBalance());\n\n if (from != sender) {\n uint256 allowed = allowance[from][sender];\n if (allowed != type(uint256).max) {\n require(allowed >= value, InsufficientAllowance());\n unchecked {\n allowance[from][sender] = allowed - value;\n }\n }\n }\n\n unchecked {\n _setBalance(from, balance - value);\n // note: we don't need an overflow check here b/c sum of all balances == totalSupply\n _setBalance(to, _balanceOf(to) + value);\n }\n\n emit Transfer(from, to, value);\n\n return true;\n }\n\n /// @inheritdoc IERC20\n function approve(address spender, uint256 value) external returns (bool) {\n allowance[msg.sender][spender] = value;\n\n emit Approval(msg.sender, spender, value);\n\n return true;\n }\n\n // --- Mint/Burn ---\n function mint(address to, uint256 value) public virtual auth {\n require(to != address(0) && to != address(this), InvalidAddress());\n unchecked {\n // We don't need an overflow check here b/c balances[to] <= totalSupply\n // and there is an overflow check below\n _setBalance(to, _balanceOf(to) + value);\n }\n totalSupply += value;\n\n emit Transfer(address(0), to, value);\n }\n\n function burn(address from, uint256 value) public virtual auth {\n uint256 balance = balanceOf(from);\n require(balance >= value, InsufficientBalance());\n\n if (from != msg.sender) {\n uint256 allowed = allowance[from][msg.sender];\n if (allowed != type(uint256).max) {\n require(allowed >= value, InsufficientAllowance());\n\n unchecked {\n allowance[from][msg.sender] = allowed - value;\n }\n }\n }\n\n unchecked {\n // We don't need overflow checks b/c require(balance >= value) and balance <= totalSupply\n _setBalance(from, balance - value);\n totalSupply -= value;\n }\n\n emit Transfer(from, address(0), value);\n }\n\n // --- Approve by signature ---\n function permit(address owner, address spender, uint256 value, uint256 deadline, bytes memory signature) public {\n require(block.timestamp <= deadline, PermitExpired());\n\n uint256 nonce;\n unchecked {\n nonce = nonces[owner]++;\n }\n\n bytes32 digest = keccak256(\n abi.encodePacked(\n \"\\x19\\x01\",\n DOMAIN_SEPARATOR(),\n keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonce, deadline))\n )\n );\n\n require(SignatureLib.isValidSignature(owner, digest, signature), InvalidPermit());\n\n allowance[owner][spender] = value;\n emit Approval(owner, spender, value);\n }\n\n /// @inheritdoc IERC20Permit\n function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)\n external\n {\n permit(owner, spender, value, deadline, abi.encodePacked(r, s, v));\n }\n}\n" + }, + "src/misc/IdentityValuation.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {d18} from \"src/misc/types/D18.sol\";\nimport {IERC7726} from \"src/misc/interfaces/IERC7726.sol\";\nimport {IIdentityValuation} from \"src/misc/interfaces/IIdentityValuation.sol\";\nimport {IERC6909Decimals} from \"src/misc/interfaces/IERC6909.sol\";\nimport {BaseValuation} from \"src/misc/BaseValuation.sol\";\n\nimport {PricingLib} from \"src/common/libraries/PricingLib.sol\";\n\ncontract IdentityValuation is BaseValuation, IIdentityValuation {\n constructor(IERC6909Decimals erc6909, address deployer) BaseValuation(erc6909, deployer) {}\n\n /// @inheritdoc IERC7726\n function getQuote(uint256 baseAmount, address base, address quote) external view returns (uint256 quoteAmount) {\n return PricingLib.convertWithPrice(baseAmount, _getDecimals(base), _getDecimals(quote), d18(1e18));\n }\n}\n" + }, + "src/misc/Multicall.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.28;\n\n// NOTE: This file has warning disabled due https://github.com/ethereum/solidity/issues/14359\n// If perform any change on it, please ensure no other warnings appears\n\nimport {IMulticall} from \"src/misc/interfaces/IMulticall.sol\";\nimport {ReentrancyProtection} from \"src/misc/ReentrancyProtection.sol\";\n\nabstract contract Multicall is ReentrancyProtection, IMulticall {\n function multicall(bytes[] calldata data) public payable virtual protected {\n uint256 totalBytes = data.length;\n for (uint256 i; i < totalBytes; ++i) {\n (bool success, bytes memory returnData) = address(this).delegatecall(data[i]);\n if (!success) {\n uint256 length = returnData.length;\n require(length != 0, CallFailedWithEmptyRevert());\n\n assembly (\"memory-safe\") {\n revert(add(32, returnData), length)\n }\n }\n }\n }\n}\n" + }, + "src/misc/Recoverable.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {IERC6909} from \"src/misc/interfaces/IERC6909.sol\";\nimport {SafeTransferLib} from \"src/misc/libraries/SafeTransferLib.sol\";\n\nimport {IRecoverable, ETH_ADDRESS} from \"src/misc/interfaces/IRecoverable.sol\";\n\nabstract contract Recoverable is Auth, IRecoverable {\n /// @inheritdoc IRecoverable\n function recoverTokens(address token, address receiver, uint256 amount) public auth {\n if (token == ETH_ADDRESS) {\n SafeTransferLib.safeTransferETH(receiver, amount);\n } else {\n SafeTransferLib.safeTransfer(token, receiver, amount);\n }\n }\n\n /// @inheritdoc IRecoverable\n function recoverTokens(address token, uint256 tokenId, address receiver, uint256 amount) external auth {\n if (tokenId == 0) {\n recoverTokens(token, receiver, amount);\n } else {\n IERC6909(token).transfer(receiver, tokenId, amount);\n }\n }\n}\n" + }, + "src/misc/ReentrancyProtection.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.28;\n\n// NOTE: This file has warning disabled due https://github.com/ethereum/solidity/issues/14359\n// If perform any change on it, please ensure no other warnings appears\n\nabstract contract ReentrancyProtection {\n /// @notice Dispatched when there is a re-entrancy issue\n error UnauthorizedSender();\n\n address private transient _initiator;\n\n /// @dev The method is protected for reentrancy issues.\n modifier protected() {\n if (_initiator == address(0)) {\n // Single call re-entrancy lock\n _initiator = msg.sender;\n _;\n _initiator = address(0);\n } else {\n // Multicall re-entrancy lock\n require(msg.sender == _initiator, UnauthorizedSender());\n _;\n }\n }\n}\n" + }, + "src/misc/interfaces/IAuth.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\ninterface IAuth {\n event Rely(address indexed user);\n event Deny(address indexed user);\n\n error NotAuthorized();\n\n /// @notice Returns whether the target is a ward (has admin access)\n function wards(address target) external view returns (uint256);\n\n /// @notice Make user a ward (give them admin access)\n function rely(address user) external;\n\n /// @notice Remove user as a ward (remove admin access)\n function deny(address user) external;\n}\n" + }, + "src/misc/interfaces/IBaseValuation.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IERC7726} from \"src/misc/interfaces/IERC7726.sol\";\n\n/// Provides a base implementation for all ERC7726 valuation in the system\ninterface IBaseValuation is IERC7726 {\n /// @notice Emitted when a call to `file()` was performed.\n event File(bytes32 indexed what, address addr);\n\n /// @notice Dispatched when the `what` parameter of `file()` is not supported by the implementation.\n error FileUnrecognizedParam();\n\n /// @notice Updates a contract parameter.\n /// @param what Name of the parameter to update.\n /// Accepts a `bytes32` representation of 'assetRegistry' string value.\n /// @param data New value given to the `what` parameter\n function file(bytes32 what, address data) external;\n}\n" + }, + "src/misc/interfaces/IERC20.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\n/// @title IERC20\n/// @dev Interface of the ERC20 standard as defined in the EIP.\n/// @author Modified from OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)\ninterface IERC20 {\n error InvalidAddress();\n error InsufficientBalance();\n error InsufficientAllowance();\n\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n error PermitExpired();\n error InvalidPermit();\n\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)\n external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\ninterface IERC20Wrapper {\n /**\n * @dev Returns the address of the underlying ERC-20 token that is being wrapped.\n */\n function underlying() external view returns (address);\n\n /**\n * @dev Allow a user to deposit underlying tokens and mint the corresponding number of wrapped tokens.\n */\n function depositFor(address account, uint256 value) external returns (bool);\n\n /**\n * @dev Allow a user to burn a number of wrapped tokens and withdraw the corresponding number of underlying tokens.\n */\n function withdrawTo(address account, uint256 value) external returns (bool);\n}\n" + }, + "src/misc/interfaces/IERC6909.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IERC165} from \"forge-std/interfaces/IERC165.sol\";\n\ninterface IERC6909 is IERC165 {\n error EmptyOwner();\n error EmptyAmount();\n error InvalidTokenId();\n error InsufficientBalance(address owner, uint256 tokenId);\n error InsufficientAllowance(address sender, uint256 tokenId);\n\n event OperatorSet(address indexed owner, address indexed operator, bool approved);\n event Approval(address indexed owner, address indexed spender, uint256 indexed tokenId, uint256 amount);\n event Transfer(address caller, address indexed from, address indexed to, uint256 indexed tokenId, uint256 amount);\n\n /// @notice Owner balance of a tokenId.\n /// @param owner The address of the owner.\n /// @param tokenId The id of the token.\n /// @return amount The balance of the token.\n function balanceOf(address owner, uint256 tokenId) external view returns (uint256 amount);\n\n /// @notice Spender allowance of a tokenId.\n /// @param owner The address of the owner.\n /// @param spender The address of the spender.\n /// @param tokenId The id of the token.\n /// @return amount The allowance of the token.\n function allowance(address owner, address spender, uint256 tokenId) external view returns (uint256 amount);\n\n /// @notice Checks if a spender is approved by an owner as an operator.\n /// @param owner The address of the owner.\n /// @param spender The address of the spender.\n /// @return approved The approval status.\n function isOperator(address owner, address spender) external view returns (bool approved);\n\n /// @notice Transfers an amount of a tokenId from the caller to a receiver.\n /// @param receiver The address of the receiver.\n /// @param tokenId The id of the token.\n /// @param amount The amount of the token.\n /// @return bool True, always, unless the function reverts.\n function transfer(address receiver, uint256 tokenId, uint256 amount) external returns (bool);\n\n /// @notice Transfers an amount of a tokenId from a sender to a receiver.\n /// @param sender The address of the sender.\n /// @param receiver The address of the receiver.\n /// @param tokenId The id of the token.\n /// @param amount The amount of the token.\n /// @return bool True, always, unless the function reverts.\n function transferFrom(address sender, address receiver, uint256 tokenId, uint256 amount) external returns (bool);\n\n /// @notice Approves an amount of a tokenId to a spender.\n /// @param spender The address of the spender.\n /// @param tokenId The id of the token.\n /// @param amount The amount of the token.\n /// @return bool True, always.\n function approve(address spender, uint256 tokenId, uint256 amount) external returns (bool);\n\n /// @notice Sets or removes an operator for the caller.\n /// @param operator The address of the operator.\n /// @param approved The approval status.\n /// @return bool True, always.\n function setOperator(address operator, bool approved) external returns (bool);\n}\n\ninterface IERC6909URIExt {\n event TokenURISet(uint256 indexed tokenId, string uri);\n event ContractURISet(address indexed target, string uri);\n\n error EmptyURI();\n\n /// @return uri Returns the common token URI.\n function contractURI() external view returns (string memory);\n\n /// @dev Returns empty string if tokenId does not exist.\n /// MAY implemented to throw MissingURI(tokenId) error.\n /// @param tokenId The token to query URI for.\n /// @return uri A string representing the uri for the specific tokenId.\n function tokenURI(uint256 tokenId) external view returns (string memory);\n}\n\ninterface IERC6909NFT is IERC6909, IERC6909URIExt {\n error UnknownTokenId(address owner, uint256 tokenId);\n error LessThanMinimalDecimal(uint8 minimal, uint8 actual);\n\n /// @notice Provide URI for a specific tokenId.\n /// @param tokenId Token Id.\n /// @param URI URI to a document defining the collection as a whole.\n function setTokenURI(uint256 tokenId, string memory URI) external;\n\n /// @dev Optional method to set up the contract URI if needed.\n /// @param URI URI to a document defining the collection as a whole.\n function setContractURI(string memory URI) external;\n\n /// @notice Mint new tokens for a given owner and sets tokenURI.\n /// @dev For non-fungible tokens, call with amount = 1, for fungible it could be any amount.\n /// TokenId is auto incremented by one.\n ///\n /// @param owner Creates supply of a given tokenId by amount for owner.\n /// @param tokenURI URI fortestBurningToken the newly minted token.\n /// @return tokenId Id of the newly minted token.\n function mint(address owner, string memory tokenURI) external returns (uint256 tokenId);\n\n /// @notice Destroy supply of a given tokenId by amount.\n /// @dev The msg.sender MUST be the owner.\n ///\n /// @param tokenId Item which have reduced supply.\n function burn(uint256 tokenId) external;\n}\n\n/// @notice Extension of ERC6909 Standard for tracking total supply\ninterface IERC6909TotalSupplyExt {\n /// @notice The totalSupply for a token id.\n ///\n /// @param tokenId Id of the token\n /// @return supply Total supply for a given `tokenId`\n function totalSupply(uint256 tokenId) external returns (uint256 supply);\n}\n\ninterface IERC6909Decimals {\n /// @notice Used to retrieve the decimals of an asset\n /// @dev address is used but the value corresponds to a AssetId\n function decimals(uint256 assetId) external view returns (uint8);\n}\n\ninterface IERC6909MetadataExt is IERC6909Decimals {\n /// @notice Used to retrieve the decimals of an asset\n /// @dev address is used but the value corresponds to a AssetId\n function decimals(uint256 assetId) external view returns (uint8);\n\n /// @notice Used to retrieve the name of an asset\n /// @dev address is used but the value corresponds to a AssetId\n function name(uint256 assetId) external view returns (string memory);\n\n /// @notice Used to retrieve the symbol of an asset\n /// @dev address is used but the value corresponds to a AssetId\n function symbol(uint256 assetId) external view returns (string memory);\n}\n\ninterface IERC6909Fungible is IERC6909 {\n /// @notice Mint new tokens for a specific tokenid and assign them to an owner\n ///\n /// @param owner Creates supply of a given `tokenId` by `amount` for owner.\n /// @param tokenId Id of the item\n /// @param amount Adds `amount` to the total supply of the given `tokenId`\n function mint(address owner, uint256 tokenId, uint256 amount) external;\n\n /// @notice Destroy supply of a given tokenId by amount.\n /// @dev The msg.sender MUST be the owner.\n ///\n /// @param owner Owner of the `tokenId`\n /// @param tokenId Id of the item.\n /// @param amount Subtract `amount` from the total supply of the given `tokenId`\n function burn(address owner, uint256 tokenId, uint256 amount) external;\n\n /// @notice Enforces a transfer from `spender` point of view.\n ///\n ///\n /// @param sender The owner of the `tokenId`\n /// @param receiver Address of the receiving party\n /// @param tokenId Token Id\n /// @param amount Amount to be transferred\n function authTransferFrom(address sender, address receiver, uint256 tokenId, uint256 amount)\n external\n returns (bool);\n}\n\n/// @dev A factory contract to deploy new collateral contracts implementing IERC6909.\ninterface IERC6909Factory {\n /// Events\n event NewTokenDeployment(address indexed owner, address instance);\n\n /// @notice Deploys new install of a contract that implements IERC6909.\n /// @dev Factory should deploy deterministically if possible.\n ///\n /// @param owner Owner of the deployed collateral contract which has initial full rights.\n /// @param salt Used to make a deterministic deployment.\n /// @return An address of the newly deployed contract.\n function deploy(address owner, bytes32 salt) external returns (address);\n\n /// @notice Generates a new deterministic address based on the owner and the salt.\n ///\n /// @param owner Owner of the deployed collateral contract which has initial full rights.\n /// @param salt Used to make a deterministic deployment.\n /// @return An address of the newly deployed contract.\n function previewAddress(address owner, bytes32 salt) external returns (address);\n}\n" + }, + "src/misc/interfaces/IERC7540.sol": { + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.5.0;\n\nimport {IRecoverable} from \"src/misc/interfaces/IRecoverable.sol\";\nimport {IERC7575, IERC165} from \"src/misc/interfaces/IERC7575.sol\";\n\ninterface IERC7540Operator {\n /**\n * @dev The event emitted when an operator is set.\n *\n * @param controller The address of the controller.\n * @param operator The address of the operator.\n * @param approved The approval status.\n */\n event OperatorSet(address indexed controller, address indexed operator, bool approved);\n\n /**\n * @dev Sets or removes an operator for the caller.\n *\n * @param operator The address of the operator.\n * @param approved The approval status.\n * @return Whether the call was executed successfully or not\n */\n function setOperator(address operator, bool approved) external returns (bool);\n\n /**\n * @dev Returns `true` if the `operator` is approved as an operator for an `controller`.\n *\n * @param controller The address of the controller.\n * @param operator The address of the operator.\n * @return status The approval status\n */\n function isOperator(address controller, address operator) external view returns (bool status);\n}\n\ninterface IERC7540Deposit is IERC7540Operator {\n event DepositRequest(\n address indexed controller, address indexed owner, uint256 indexed requestId, address sender, uint256 assets\n );\n /**\n * @dev Transfers assets from sender into the Vault and submits a Request for asynchronous deposit.\n *\n * - MUST support ERC-20 approve / transferFrom on asset as a deposit Request flow.\n * - MUST revert if all of assets cannot be requested for deposit.\n * - owner MUST be msg.sender unless some unspecified explicit approval is given by the caller,\n * approval of ERC-20 tokens from owner to sender is NOT enough.\n *\n * @param assets the amount of deposit assets to transfer from owner\n * @param controller the controller of the request who will be able to operate the request\n * @param owner the source of the deposit assets\n *\n * NOTE: most implementations will require pre-approval of the Vault with the Vault's underlying asset token.\n */\n\n function requestDeposit(uint256 assets, address controller, address owner) external returns (uint256 requestId);\n\n /**\n * @dev Returns the amount of requested assets in Pending state.\n *\n * - MUST NOT include any assets in Claimable state for deposit or mint.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT revert unless due to integer overflow caused by an unreasonably large input.\n */\n function pendingDepositRequest(uint256 requestId, address controller)\n external\n view\n returns (uint256 pendingAssets);\n\n /**\n * @dev Returns the amount of requested assets in Claimable state for the controller to deposit or mint.\n *\n * - MUST NOT include any assets in Pending state.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT revert unless due to integer overflow caused by an unreasonably large input.\n */\n function claimableDepositRequest(uint256 requestId, address controller)\n external\n view\n returns (uint256 claimableAssets);\n\n /**\n * @dev Mints shares Vault shares to receiver by claiming the Request of the controller.\n *\n * - MUST emit the Deposit event.\n * - controller MUST equal msg.sender unless the controller has approved the msg.sender as an operator.\n */\n function deposit(uint256 assets, address receiver, address controller) external returns (uint256 shares);\n\n /**\n * @dev Mints exactly shares Vault shares to receiver by claiming the Request of the controller.\n *\n * - MUST emit the Deposit event.\n * - controller MUST equal msg.sender unless the controller has approved the msg.sender as an operator.\n */\n function mint(uint256 shares, address receiver, address controller) external returns (uint256 assets);\n}\n\ninterface IERC7540Redeem is IERC7540Operator {\n event RedeemRequest(\n address indexed controller, address indexed owner, uint256 indexed requestId, address sender, uint256 assets\n );\n\n /**\n * @dev Assumes control of shares from sender into the Vault and submits a Request for asynchronous redeem.\n *\n * - MUST support a redeem Request flow where the control of shares is taken from sender directly\n * where msg.sender has ERC-20 approval over the shares of owner.\n * - MUST revert if all of shares cannot be requested for redeem.\n *\n * @param shares the amount of shares to be redeemed to transfer from owner\n * @param controller the controller of the request who will be able to operate the request\n * @param owner the source of the shares to be redeemed\n *\n * NOTE: most implementations will require pre-approval of the Vault with the Vault's share token.\n */\n function requestRedeem(uint256 shares, address controller, address owner) external returns (uint256 requestId);\n\n /**\n * @dev Returns the amount of requested shares in Pending state.\n *\n * - MUST NOT include any shares in Claimable state for redeem or withdraw.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT revert unless due to integer overflow caused by an unreasonably large input.\n */\n function pendingRedeemRequest(uint256 requestId, address controller)\n external\n view\n returns (uint256 pendingShares);\n\n /**\n * @dev Returns the amount of requested shares in Claimable state for the controller to redeem or withdraw.\n *\n * - MUST NOT include any shares in Pending state for redeem or withdraw.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT revert unless due to integer overflow caused by an unreasonably large input.\n */\n function claimableRedeemRequest(uint256 requestId, address controller)\n external\n view\n returns (uint256 claimableShares);\n}\n\ninterface IERC7887Deposit {\n event CancelDepositRequest(address indexed controller, uint256 indexed requestId, address sender);\n event CancelDepositClaim(\n address indexed controller, address indexed receiver, uint256 indexed requestId, address sender, uint256 assets\n );\n\n /**\n * @dev Submits a Request for cancelling the pending deposit Request\n *\n * - controller MUST be msg.sender unless some unspecified explicit approval is given by the caller,\n * approval of ERC-20 tokens from controller to sender is NOT enough.\n * - MUST set pendingCancelDepositRequest to `true` for the returned requestId after request\n * - MUST increase claimableCancelDepositRequest for the returned requestId after fulfillment\n * - SHOULD be claimable using `claimCancelDepositRequest`\n * Note: while `pendingCancelDepositRequest` is `true`, `requestDeposit` cannot be called\n */\n function cancelDepositRequest(uint256 requestId, address controller) external;\n\n /**\n * @dev Returns whether the deposit Request is pending cancelation\n *\n * - MUST NOT show any variations depending on the caller.\n */\n function pendingCancelDepositRequest(uint256 requestId, address controller)\n external\n view\n returns (bool isPending);\n\n /**\n * @dev Returns the amount of assets that were canceled from a deposit Request, and can now be claimed.\n *\n * - MUST NOT show any variations depending on the caller.\n */\n function claimableCancelDepositRequest(uint256 requestId, address controller)\n external\n view\n returns (uint256 claimableAssets);\n\n /**\n * @dev Claims the canceled deposit assets, and removes the pending cancelation Request\n *\n * - controller MUST be msg.sender unless some unspecified explicit approval is given by the caller,\n * approval of ERC-20 tokens from controller to sender is NOT enough.\n * - MUST set pendingCancelDepositRequest to `false` for the returned requestId after request\n * - MUST set claimableCancelDepositRequest to 0 for the returned requestId after fulfillment\n */\n function claimCancelDepositRequest(uint256 requestId, address receiver, address controller)\n external\n returns (uint256 assets);\n}\n\ninterface IERC7887Redeem {\n event CancelRedeemRequest(address indexed controller, uint256 indexed requestId, address sender);\n event CancelRedeemClaim(\n address indexed controller, address indexed receiver, uint256 indexed requestId, address sender, uint256 shares\n );\n\n /**\n * @dev Submits a Request for cancelling the pending redeem Request\n *\n * - controller MUST be msg.sender unless some unspecified explicit approval is given by the caller,\n * approval of ERC-20 tokens from controller to sender is NOT enough.\n * - MUST set pendingCancelRedeemRequest to `true` for the returned requestId after request\n * - MUST increase claimableCancelRedeemRequest for the returned requestId after fulfillment\n * - SHOULD be claimable using `claimCancelRedeemRequest`\n * Note: while `pendingCancelRedeemRequest` is `true`, `requestRedeem` cannot be called\n */\n function cancelRedeemRequest(uint256 requestId, address controller) external;\n\n /**\n * @dev Returns whether the redeem Request is pending cancelation\n *\n * - MUST NOT show any variations depending on the caller.\n */\n function pendingCancelRedeemRequest(uint256 requestId, address controller) external view returns (bool isPending);\n\n /**\n * @dev Returns the amount of shares that were canceled from a redeem Request, and can now be claimed.\n *\n * - MUST NOT show any variations depending on the caller.\n */\n function claimableCancelRedeemRequest(uint256 requestId, address controller)\n external\n view\n returns (uint256 claimableShares);\n\n /**\n * @dev Claims the canceled redeem shares, and removes the pending cancelation Request\n *\n * - controller MUST be msg.sender unless some unspecified explicit approval is given by the caller,\n * approval of ERC-20 tokens from controller to sender is NOT enough.\n * - MUST set pendingCancelRedeemRequest to `false` for the returned requestId after request\n * - MUST set claimableCancelRedeemRequest to 0 for the returned requestId after fulfillment\n */\n function claimCancelRedeemRequest(uint256 requestId, address receiver, address controller)\n external\n returns (uint256 shares);\n}\n\ninterface IERC7741 {\n /**\n * @dev Grants or revokes permissions for `operator` to manage Requests on behalf of the\n * `msg.sender`, using an [EIP-712](./eip-712.md) signature.\n */\n function authorizeOperator(\n address controller,\n address operator,\n bool approved,\n bytes32 nonce,\n uint256 deadline,\n bytes memory signature\n ) external returns (bool);\n\n /**\n * @dev Revokes the given `nonce` for `msg.sender` as the `owner`.\n */\n function invalidateNonce(bytes32 nonce) external;\n\n /**\n * @dev Returns whether the given `nonce` has been used for the `controller`.\n */\n function authorizations(address controller, bytes32 nonce) external view returns (bool used);\n\n /**\n * @dev Returns the `DOMAIN_SEPARATOR` as defined according to EIP-712. The `DOMAIN_SEPARATOR\n * should be unique to the contract and chain to prevent replay attacks from other domains,\n * and satisfy the requirements of EIP-712, but is otherwise unconstrained.\n */\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\ninterface IERC7714 {\n /**\n * @dev Returns `true` if the `user` is permissioned to interact with the contract.\n */\n function isPermissioned(address controller) external view returns (bool);\n}\n" + }, + "src/misc/interfaces/IERC7575.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\ninterface IERC7575 is IERC165 {\n event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares);\n event Withdraw(\n address indexed sender, address indexed receiver, address indexed owner, uint256 assets, uint256 shares\n );\n\n /**\n * @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.\n *\n * - MUST be an ERC-20 token contract.\n * - MUST NOT revert.\n */\n function asset() external view returns (address assetTokenAddress);\n\n /**\n * @dev Returns the address of the share token\n *\n * - MUST be an ERC-20 token contract.\n * - MUST NOT revert.\n */\n function share() external view returns (address shareTokenAddress);\n\n /**\n * @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal\n * scenario where all the conditions are met.\n *\n * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.\n * - MUST NOT revert.\n *\n * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the\n * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and\n * from.\n */\n function convertToShares(uint256 assets) external view returns (uint256 shares);\n\n /**\n * @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal\n * scenario where all the conditions are met.\n *\n * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.\n * - MUST NOT revert.\n *\n * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the\n * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and\n * from.\n */\n function convertToAssets(uint256 shares) external view returns (uint256 assets);\n\n /**\n * @dev Returns the total amount of the underlying asset that is “managed” by Vault.\n *\n * - SHOULD include any compounding that occurs from yield.\n * - MUST be inclusive of any fees that are charged against assets in the Vault.\n * - MUST NOT revert.\n */\n function totalAssets() external view returns (uint256 totalManagedAssets);\n\n /**\n * @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,\n * through a deposit call.\n *\n * - MUST return a limited value if receiver is subject to some deposit limit.\n * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.\n * - MUST NOT revert.\n */\n function maxDeposit(address receiver) external view returns (uint256 maxAssets);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given\n * current on-chain conditions.\n *\n * - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit\n * call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called\n * in the same transaction.\n * - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the\n * deposit would be accepted, regardless if the user has enough tokens approved, etc.\n * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by depositing.\n */\n function previewDeposit(uint256 assets) external view returns (uint256 shares);\n\n /**\n * @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens.\n *\n * - MUST emit the Deposit event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n * deposit execution, and are accounted for during deposit.\n * - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not\n * approving enough underlying tokens to the Vault contract, etc).\n *\n * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.\n */\n function deposit(uint256 assets, address receiver) external returns (uint256 shares);\n\n /**\n * @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.\n * - MUST return a limited value if receiver is subject to some mint limit.\n * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.\n * - MUST NOT revert.\n */\n function maxMint(address receiver) external view returns (uint256 maxShares);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given\n * current on-chain conditions.\n *\n * - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call\n * in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the\n * same transaction.\n * - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint\n * would be accepted, regardless if the user has enough tokens approved, etc.\n * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by minting.\n */\n function previewMint(uint256 shares) external view returns (uint256 assets);\n\n /**\n * @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.\n *\n * - MUST emit the Deposit event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint\n * execution, and are accounted for during mint.\n * - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not\n * approving enough underlying tokens to the Vault contract, etc).\n *\n * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.\n */\n function mint(uint256 shares, address receiver) external returns (uint256 assets);\n\n /**\n * @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the\n * Vault, through a withdraw call.\n *\n * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.\n * - MUST NOT revert.\n */\n function maxWithdraw(address owner) external view returns (uint256 maxAssets);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,\n * given current on-chain conditions.\n *\n * - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw\n * call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if\n * called\n * in the same transaction.\n * - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though\n * the withdrawal would be accepted, regardless if the user has enough shares, etc.\n * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by depositing.\n */\n function previewWithdraw(uint256 assets) external view returns (uint256 shares);\n\n /**\n * @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver.\n *\n * - MUST emit the Withdraw event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n * withdraw execution, and are accounted for during withdraw.\n * - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner\n * not having enough shares, etc).\n *\n * Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.\n * Those methods should be performed separately.\n */\n function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares);\n\n /**\n * @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault,\n * through a redeem call.\n *\n * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.\n * - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock.\n * - MUST NOT revert.\n */\n function maxRedeem(address owner) external view returns (uint256 maxShares);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block,\n * given current on-chain conditions.\n *\n * - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call\n * in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the\n * same transaction.\n * - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the\n * redemption would be accepted, regardless if the user has enough shares, etc.\n * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by redeeming.\n */\n function previewRedeem(uint256 shares) external view returns (uint256 assets);\n\n /**\n * @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver.\n *\n * - MUST emit the Withdraw event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n * redeem execution, and are accounted for during redeem.\n * - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner\n * not having enough shares, etc).\n *\n * NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed.\n * Those methods should be performed separately.\n */\n function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets);\n}\n\ninterface IERC7575Share is IERC165 {\n event VaultUpdate(address indexed asset, address vault);\n\n /**\n * @dev Returns the address of the Vault for the given asset.\n *\n * @param asset the ERC-20 token to deposit with into the Vault\n */\n function vault(address asset) external view returns (address);\n}\n" + }, + "src/misc/interfaces/IERC7726.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\n/// [ERC-7726](https://eips.ethereum.org/EIPS/eip-7726): Common Quote Oracle\n/// Interface for asset conversions.\ninterface IERC7726 {\n /// @notice Returns the value of baseAmount of base in quote terms, e.g. 10 ETH (base) in USDC (quote).\n /// @param base The asset in which the baseAmount is denominated in\n /// @param quote The asset in which the user needs to value the baseAmount\n /// @param baseAmount The amount of base in base terms.\n function getQuote(uint256 baseAmount, address base, address quote) external view returns (uint256 quoteAmount);\n}\n" + }, + "src/misc/interfaces/IIdentityValuation.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IERC7726} from \"src/misc/interfaces/IERC7726.sol\";\n\n/// @notice An IERC7726 valuation that always values 1:1.\ninterface IIdentityValuation is IERC7726 {}\n" + }, + "src/misc/interfaces/IMulticall.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\n/// @notice Allows to call several calls of the same contract in a single transaction\ninterface IMulticall {\n /// @notice Dispatched when an empty revert is dispatched in a method in the multicall\n error CallFailedWithEmptyRevert();\n\n /// @notice Allows caller to execute multiple (batched) messages calls in one transaction.\n /// @param data An array of encoded methods of the same contract.\n /// @dev No reentrant execution is allowed.\n /// If one call fails, it reverts the whole transaction.\n /// In order to provide the correct value for functions that require top up,\n /// the caller must estimate separately, in advance, how much each of the message call will cost.\n /// The `msg.value` when calling this method must be the sum of all estimates.\n function multicall(bytes[] calldata data) external payable;\n}\n" + }, + "src/misc/interfaces/IRecoverable.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\naddress constant ETH_ADDRESS = address(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);\n\ninterface IRecoverable {\n /// @notice Used to recover any ERC-20 token.\n /// @dev This method is called only by authorized entities\n /// @param token It could be 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee\n /// to recover locked native ETH or token compatible with ERC20.\n /// @param to Receiver of the funds\n /// @param amount Amount to send to the receiver.\n function recoverTokens(address token, address to, uint256 amount) external;\n\n /// @notice Used to recover any ERC-20 or ERC-6909 token.\n /// @dev This method is called only by authorized entities\n /// @param token It could be 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee\n /// to recover locked native ETH or token compatible with ERC20 or ERC6909.\n /// @param tokenId The token id, i.e. non-zero if the underlying token is ERC6909 and else zero.\n /// @param to Receiver of the funds\n /// @param amount Amount to send to the receiver.\n function recoverTokens(address token, uint256 tokenId, address to, uint256 amount) external;\n}\n" + }, + "src/misc/libraries/ArrayLib.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\n/// @title ArrayLib\nlibrary ArrayLib {\n error InvalidValues();\n\n function countNonZeroValues(uint16[8] memory arr) internal pure returns (uint8 count) {\n uint256 elementsCount = arr.length;\n for (uint256 i; i < elementsCount; i++) {\n if (arr[i] != 0) ++count;\n }\n }\n\n function decreaseFirstNValues(uint16[8] storage arr, uint8 numValues) internal {\n uint256 elementsCount = arr.length;\n for (uint256 i; i < elementsCount; i++) {\n if (numValues == 0) return;\n\n if (arr[i] != 0) {\n arr[i] -= 1;\n numValues--;\n }\n }\n\n require(numValues == 0, InvalidValues());\n }\n\n function isEmpty(uint16[8] memory arr) internal pure returns (bool) {\n uint256 elementsCount = arr.length;\n for (uint256 i; i < elementsCount; i++) {\n if (arr[i] != 0) return false;\n }\n return true;\n }\n}\n" + }, + "src/misc/libraries/BitmapLib.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\n/// @title BitmapLib\nlibrary BitmapLib {\n function setBit(uint128 bitmap, uint128 index, bool isTrue) internal pure returns (uint128) {\n if (isTrue) {\n return bitmap | (uint128(1) << index);\n }\n\n return bitmap & ~(uint128(1) << index);\n }\n\n function getBit(uint128 bitmap, uint128 index) internal pure returns (bool) {\n uint128 bitAtIndex = uint128(bitmap & (1 << index));\n return bitAtIndex != 0;\n }\n}\n" + }, + "src/misc/libraries/BytesLib.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\n/// @title Bytes Lib\n/// @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity.\n/// The library lets you concatenate, slice and type cast bytes arrays both in memory and storage.\n/// @author Modified from Solidity Bytes Arrays Utils v0.8.0\nlibrary BytesLib {\n error SliceOverflow();\n error SliceOutOfBounds();\n\n function sliceZeroPadded(bytes memory _bytes, uint256 _start, uint256 _length)\n internal\n pure\n returns (bytes memory)\n {\n require(_length + 31 >= _length, SliceOverflow());\n\n bytes memory tempBytes;\n\n assembly {\n switch iszero(_length)\n case 0 {\n // Get a location of some free memory and store it in tempBytes as\n // Solidity does for memory variables.\n tempBytes := mload(0x40)\n\n // The first word of the slice result is potentially a partial\n // word read from the original array. To read it, we calculate\n // the length of that partial word and start copying that many\n // bytes into the array. The first word we copy will start with\n // data we don't care about, but the last `lengthmod` bytes will\n // land at the beginning of the contents of the new array. When\n // we're done copying, we overwrite the full first word with\n // the actual length of the slice.\n let lengthmod := and(_length, 31)\n\n // The multiplication in the next line is necessary\n // because when slicing multiples of 32 bytes (lengthmod == 0)\n // the following copy loop was copying the origin's length\n // and then ending prematurely not copying everything it should.\n let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))\n let end := add(mc, _length)\n\n for {\n // The multiplication in the next line has the same exact purpose\n // as the one above.\n let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)\n } lt(mc, end) {\n mc := add(mc, 0x20)\n cc := add(cc, 0x20)\n } { mstore(mc, mload(cc)) }\n\n mstore(tempBytes, _length)\n\n //update free-memory pointer\n //allocating the array padded to 32 bytes like the compiler does now\n mstore(0x40, and(add(mc, 31), not(31)))\n }\n //if we want a zero-length slice let's just return a zero-length array\n default {\n tempBytes := mload(0x40)\n //zero out the 32 bytes slice we are about to return\n //we need to do it because Solidity does not garbage collect\n mstore(tempBytes, 0)\n\n mstore(0x40, add(tempBytes, 0x20))\n }\n }\n\n return tempBytes;\n }\n\n function slice(bytes memory _bytes, uint256 _start, uint256 _length) internal pure returns (bytes memory) {\n require(_bytes.length >= _start + _length, SliceOutOfBounds());\n return sliceZeroPadded(_bytes, _start, _length);\n }\n\n function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) {\n require(_bytes.length >= _start + 20, SliceOutOfBounds());\n address tempAddress;\n\n assembly {\n tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000)\n }\n\n return tempAddress;\n }\n\n function toUint8(bytes memory _bytes, uint256 _start) internal pure returns (uint8) {\n require(_bytes.length >= _start + 1, SliceOutOfBounds());\n uint8 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x1), _start))\n }\n\n return tempUint;\n }\n\n function toUint16(bytes memory _bytes, uint256 _start) internal pure returns (uint16) {\n require(_bytes.length >= _start + 2, SliceOutOfBounds());\n uint16 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x2), _start))\n }\n\n return tempUint;\n }\n\n function toUint32(bytes memory _bytes, uint256 _start) internal pure returns (uint32) {\n require(_bytes.length >= _start + 4, SliceOutOfBounds());\n uint32 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x4), _start))\n }\n\n return tempUint;\n }\n\n function toUint64(bytes memory _bytes, uint256 _start) internal pure returns (uint64) {\n require(_bytes.length >= _start + 8, SliceOutOfBounds());\n uint64 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x8), _start))\n }\n\n return tempUint;\n }\n\n function toUint128(bytes memory _bytes, uint256 _start) internal pure returns (uint128) {\n require(_bytes.length >= _start + 16, SliceOutOfBounds());\n uint128 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x10), _start))\n }\n\n return tempUint;\n }\n\n function toUint256(bytes memory _bytes, uint256 _start) internal pure returns (uint256) {\n require(_bytes.length >= _start + 32, SliceOutOfBounds());\n uint256 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x20), _start))\n }\n\n return tempUint;\n }\n\n function toBytes32(bytes memory _bytes, uint256 _start) internal pure returns (bytes32) {\n require(_bytes.length >= _start + 32, SliceOutOfBounds());\n bytes32 tempBytes32;\n\n assembly {\n tempBytes32 := mload(add(add(_bytes, 0x20), _start))\n }\n\n return tempBytes32;\n }\n\n function toBytes16(bytes memory _bytes, uint256 _start) internal pure returns (bytes16) {\n require(_bytes.length >= _start + 16, SliceOutOfBounds());\n bytes16 tempBytes16;\n\n assembly {\n tempBytes16 := mload(add(add(_bytes, 0x20), _start))\n }\n\n return tempBytes16;\n }\n\n function toBool(bytes memory _bytes, uint256 _start) internal pure returns (bool) {\n require(_bytes.length > _start, SliceOutOfBounds());\n return _bytes[_start] != 0;\n }\n}\n" + }, + "src/misc/libraries/CastLib.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\n/// @title CastLib\nlibrary CastLib {\n function toAddressLeftPadded(bytes32 addr) internal pure returns (address) {\n require(bytes12(addr) == 0, \"First 12 bytes should be zero\");\n return address(uint160(uint256(addr)));\n }\n\n function toBytes32LeftPadded(address addr) internal pure returns (bytes32) {\n return bytes32(uint256(uint160(addr)));\n }\n\n function toAddress(bytes32 addr) internal pure returns (address) {\n require(uint96(uint256(addr)) == 0, \"Input should be 20 bytes\");\n return address(bytes20(addr));\n }\n\n function toString(address addr) internal pure returns (string memory) {\n return string(abi.encodePacked(addr));\n }\n\n function toBytes32(address addr) internal pure returns (bytes32) {\n return bytes32(bytes20(addr));\n }\n\n /// @dev Adds zero padding\n function toBytes32(string memory source) internal pure returns (bytes32) {\n return bytes32(bytes(source));\n }\n\n /// @dev Removes zero padding\n function bytes128ToString(bytes memory _bytes128) internal pure returns (string memory) {\n require(_bytes128.length == 128, \"Input should be 128 bytes\");\n\n uint8 i = 0;\n while (i < 128 && _bytes128[i] != 0) {\n i++;\n }\n\n bytes memory bytesArray = new bytes(i);\n\n for (uint8 j; j < i; j++) {\n bytesArray[j] = _bytes128[j];\n }\n\n return string(bytesArray);\n }\n\n function toString(bytes32 _bytes32) internal pure returns (string memory) {\n uint8 i = 0;\n while (i < 32 && _bytes32[i] != 0) {\n i++;\n }\n bytes memory bytesArray = new bytes(i);\n for (i = 0; i < 32 && _bytes32[i] != 0; i++) {\n bytesArray[i] = _bytes32[i];\n }\n return string(bytesArray);\n }\n}\n" + }, + "src/misc/libraries/EIP712Lib.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\n/// @title EIP712 Lib\nlibrary EIP712Lib {\n // keccak256(\"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\")\n bytes32 public constant EIP712_DOMAIN_TYPEHASH = 0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f;\n\n function calculateDomainSeparator(bytes32 nameHash, bytes32 versionHash) internal view returns (bytes32) {\n return keccak256(abi.encode(EIP712_DOMAIN_TYPEHASH, nameHash, versionHash, block.chainid, address(this)));\n }\n}\n" + }, + "src/misc/libraries/MathLib.sol": { + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.28;\n\nlibrary MathLib {\n enum Rounding {\n Down, // Toward negative infinity\n Up, // Toward infinity\n Zero // Toward zero\n\n }\n\n error MulDiv_Overflow();\n error Uint8_Overflow();\n error Uint32_Overflow();\n error Uint64_Overflow();\n error Uint128_Overflow();\n error Int128_Overflow();\n\n uint256 public constant One27 = 10 ** 27;\n\n /// @notice Returns x^n with rounding precision of base\n ///\n /// @dev Source: https://github.com/makerdao/dss/blob/fa4f6630afb0624d04a003e920b0d71a00331d98/src/jug.sol#L62\n ///\n /// @param x The base value which should be exponentiated\n /// @param n The exponent\n /// @param base The scaling base, typically used for fix-point calculations\n function rpow(uint256 x, uint256 n, uint256 base) public pure returns (uint256 z) {\n assembly {\n switch x\n case 0 {\n switch n\n case 0 { z := base }\n default { z := 0 }\n }\n default {\n switch mod(n, 2)\n case 0 { z := base }\n default { z := x }\n let half := div(base, 2) // for rounding.\n for { n := div(n, 2) } n { n := div(n, 2) } {\n let xx := mul(x, x)\n if iszero(eq(div(xx, x), x)) { revert(0, 0) }\n let xxRound := add(xx, half)\n if lt(xxRound, xx) { revert(0, 0) }\n x := div(xxRound, base)\n if mod(n, 2) {\n let zx := mul(z, x)\n if and(iszero(iszero(x)), iszero(eq(div(zx, x), z))) { revert(0, 0) }\n let zxRound := add(zx, half)\n if lt(zxRound, zx) { revert(0, 0) }\n z := div(zxRound, base)\n }\n }\n }\n }\n }\n\n /// @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or\n /// denominator == 0\n /// @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\n /// with further edits by Uniswap Labs also under MIT license.\n // slither-disable-start divide-before-multiply\n function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {\n unchecked {\n // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\n // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\n // variables such that product = prod1 * 2^256 + prod0.\n uint256 prod0; // Least significant 256 bits of the product\n uint256 prod1; // Most significant 256 bits of the product\n assembly {\n let mm := mulmod(x, y, not(0))\n prod0 := mul(x, y)\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n }\n\n // Handle non-overflow cases, 256 by 256 division.\n if (prod1 == 0) {\n // Solidity will revert if denominator == 0, unlike the div opcode on its own.\n // The surrounding unchecked block does not change this fact.\n // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.\n return prod0 / denominator;\n }\n\n // Make sure the result is less than 2^256. Also prevents denominator == 0.\n require(denominator > prod1, MulDiv_Overflow());\n\n ///////////////////////////////////////////////\n // 512 by 256 division.\n ///////////////////////////////////////////////\n\n // Make division exact by subtracting the remainder from [prod1 prod0].\n uint256 remainder;\n assembly {\n // Compute remainder using mulmod.\n remainder := mulmod(x, y, denominator)\n\n // Subtract 256 bit number from 512 bit number.\n prod1 := sub(prod1, gt(remainder, prod0))\n prod0 := sub(prod0, remainder)\n }\n\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator.\n // Always >= 1.\n // See https://cs.stackexchange.com/q/138556/92363.\n\n // Does not overflow because the denominator cannot be zero at this stage in the function.\n uint256 twos = denominator & (~denominator + 1);\n assembly {\n // Divide denominator by twos.\n denominator := div(denominator, twos)\n\n // Divide [prod1 prod0] by twos.\n prod0 := div(prod0, twos)\n\n // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\n twos := add(div(sub(0, twos), twos), 1)\n }\n\n // Shift in bits from prod1 into prod0.\n prod0 |= prod1 * twos;\n\n // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\n // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\n // four bits. That is, denominator * inv = 1 mod 2^4.\n uint256 inverse = (3 * denominator) ^ 2;\n\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also\n // works\n // in modular arithmetic, doubling the correct bits in each step.\n inverse *= 2 - denominator * inverse; // inverse mod 2^8\n inverse *= 2 - denominator * inverse; // inverse mod 2^16\n inverse *= 2 - denominator * inverse; // inverse mod 2^32\n inverse *= 2 - denominator * inverse; // inverse mod 2^64\n inverse *= 2 - denominator * inverse; // inverse mod 2^128\n inverse *= 2 - denominator * inverse; // inverse mod 2^256\n\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\n // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\n // is no longer required.\n result = prod0 * inverse;\n return result;\n }\n }\n // slither-disable-end divide-before-multiply\n\n /// @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\n function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {\n uint256 result = mulDiv(x, y, denominator);\n if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\n result += 1;\n }\n return result;\n }\n\n /// @notice Safe type conversion from uint256 to uint8.\n function toUint8(uint256 value) internal pure returns (uint8) {\n require(value <= type(uint8).max, Uint8_Overflow());\n return uint8(value);\n }\n\n function toUint32(uint256 value) internal pure returns (uint32) {\n require(value <= type(uint32).max, Uint32_Overflow());\n return uint32(value);\n }\n\n function toUint64(uint256 value) internal pure returns (uint64) {\n require(value <= type(uint64).max, Uint64_Overflow());\n return uint64(value);\n }\n\n /// @notice Safe type conversion from uint256 to uint128.\n function toUint128(uint256 value) internal pure returns (uint128) {\n require(value <= type(uint128).max, Uint128_Overflow());\n return uint128(value);\n }\n\n /// @notice Returns the smallest of two numbers.\n function min(uint256 a, uint256 b) internal pure returns (uint256) {\n return a > b ? b : a;\n }\n\n /// @notice Returns the largest of two numbers.\n function max(uint256 a, uint256 b) internal pure returns (uint256) {\n return a > b ? a : b;\n }\n}\n" + }, + "src/misc/libraries/SafeTransferLib.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IERC20} from \"src/misc/interfaces/IERC20.sol\";\n\n/// @title Safe Transfer Lib\n/// @author Modified from Uniswap v3 Periphery (libraries/TransferHelper.sol)\nlibrary SafeTransferLib {\n error NoCode();\n error SafeTransferFromFailed();\n error SafeTransferFailed();\n error SafeApproveFailed();\n error SafeTransferEthFailed();\n\n /// @notice Transfers tokens from the targeted address to the given destination\n /// @notice Errors if transfer fails\n /// @param token The contract address of the token to be transferred\n /// @param from The originating address from which the tokens will be transferred\n /// @param to The destination address of the transfer\n /// @param value The amount to be transferred\n function safeTransferFrom(address token, address from, address to, uint256 value) internal {\n require(address(token).code.length > 0, NoCode());\n\n (bool success, bytes memory data) = token.call(abi.encodeCall(IERC20.transferFrom, (from, to, value)));\n require(success && (data.length == 0 || abi.decode(data, (bool))), SafeTransferFromFailed());\n }\n\n /// @notice Transfers tokens from msg.sender to a recipient\n /// @dev Errors if transfer fails\n /// @param token The contract address of the token which will be transferred\n /// @param to The recipient of the transfer\n /// @param value The value of the transfer\n function safeTransfer(address token, address to, uint256 value) internal {\n require(address(token).code.length > 0, NoCode());\n\n (bool success, bytes memory data) = token.call(abi.encodeCall(IERC20.transfer, (to, value)));\n require(success && (data.length == 0 || abi.decode(data, (bool))), SafeTransferFailed());\n }\n\n /// @notice Approves the stipulated contract to spend the given allowance in the given token\n /// @dev Errors if approval fails\n /// @param token The contract address of the token to be approved\n /// @param to The target of the approval\n /// @param value The amount of the given token the target will be allowed to spend\n function safeApprove(address token, address to, uint256 value) internal {\n require(address(token).code.length > 0, NoCode());\n\n (bool success, bytes memory data) = token.call(abi.encodeCall(IERC20.approve, (to, value)));\n require(success && (data.length == 0 || abi.decode(data, (bool))), SafeApproveFailed());\n }\n\n /// @notice Transfers ETH to the recipient address\n /// @dev Fails with `STE`\n /// @dev Make sure that method that is using this function is protected from reentrancy\n /// @param to The destination of the transfer\n /// @param value The value to be transferred\n function safeTransferETH(address to, uint256 value) internal {\n (bool success,) = to.call{value: value}(new bytes(0));\n require(success, SafeTransferEthFailed());\n }\n}\n" + }, + "src/misc/libraries/SignatureLib.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\ninterface IERC1271 {\n function isValidSignature(bytes32, bytes memory) external view returns (bytes4);\n}\n\n/// @title Signature Lib\nlibrary SignatureLib {\n error InvalidSigner();\n\n function isValidSignature(address signer, bytes32 digest, bytes memory signature)\n internal\n view\n returns (bool valid)\n {\n require(signer != address(0), InvalidSigner());\n\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n if (signer == ecrecover(digest, v, r, s)) {\n return true;\n }\n }\n\n if (signer.code.length > 0) {\n (bool success, bytes memory result) =\n signer.staticcall(abi.encodeCall(IERC1271.isValidSignature, (digest, signature)));\n valid =\n (success && result.length == 32 && abi.decode(result, (bytes4)) == IERC1271.isValidSignature.selector);\n }\n }\n}\n" + }, + "src/misc/libraries/StringLib.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nlibrary StringLib {\n function isEmpty(string memory value) internal pure returns (bool) {\n return bytes(value).length == 0;\n }\n}\n" + }, + "src/misc/libraries/TransientArrayLib.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {TransientStorageLib} from \"src/misc/libraries/TransientStorageLib.sol\";\n\n/// @title TransientArrayLib\nlibrary TransientArrayLib {\n using TransientStorageLib for bytes32;\n\n function push(bytes32 key, bytes32 value) internal {\n bytes32 lengthSlot = keccak256(abi.encodePacked(key, type(uint256).max));\n uint256 length_ = lengthSlot.tloadUint256();\n lengthSlot.tstore(length_ + 1);\n\n bytes32 slot = keccak256(abi.encodePacked(key, length_));\n slot.tstore(value);\n }\n\n function getBytes32(bytes32 key) internal view returns (bytes32[] memory) {\n uint256 length_ = length(key);\n\n bytes32[] memory data = new bytes32[](length_);\n for (uint256 i = 0; i < length_; i++) {\n bytes32 slot = keccak256(abi.encodePacked(key, i));\n data[i] = slot.tloadBytes32();\n }\n\n return data;\n }\n\n function length(bytes32 key) internal view returns (uint256) {\n return keccak256(abi.encodePacked(key, type(uint256).max)).tloadUint256();\n }\n\n function clear(bytes32 key) internal {\n bytes32 lengthSlot = keccak256(abi.encodePacked(key, type(uint256).max));\n lengthSlot.tstore(uint256(0));\n }\n}\n" + }, + "src/misc/libraries/TransientBytesLib.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\nimport {TransientStorageLib} from \"src/misc/libraries/TransientStorageLib.sol\";\n\n/// @title TransientBytesLib\nlibrary TransientBytesLib {\n using TransientStorageLib for bytes32;\n using BytesLib for bytes;\n\n function append(bytes32 key, bytes memory value) internal {\n bytes32 lengthSlot = keccak256(abi.encodePacked(key, type(uint256).max));\n uint256 prevLength = lengthSlot.tloadUint256();\n\n uint256 startChunk = prevLength / 32;\n uint256 offset = prevLength % 32;\n\n lengthSlot.tstore(prevLength + value.length);\n\n bytes32 joinSlot = keccak256(abi.encodePacked(key, startChunk));\n bytes memory firstPart = abi.encodePacked(joinSlot.tloadBytes32()).sliceZeroPadded(0, offset);\n bytes memory secondPart = value.sliceZeroPadded(0, 32 - offset);\n joinSlot.tstore(bytes32(bytes.concat(firstPart, secondPart)));\n\n uint256 valueOffset = 32 - offset;\n uint256 chunkIndex = startChunk + 1;\n for (; valueOffset < value.length; chunkIndex++) {\n bytes32 slot = keccak256(abi.encodePacked(key, chunkIndex));\n slot.tstore(bytes32(value.sliceZeroPadded(valueOffset, 32)));\n valueOffset += 32;\n }\n }\n\n function get(bytes32 key) internal view returns (bytes memory) {\n bytes memory data;\n uint256 length = keccak256(abi.encodePacked(key, type(uint256).max)).tloadUint256();\n if (length == 0) return data;\n\n uint256 chunks = length / 32 + 1;\n for (uint256 i = 0; i < chunks; i++) {\n bytes32 slot = keccak256(abi.encodePacked(key, i));\n data = bytes.concat(data, slot.tloadBytes32());\n }\n\n return data.slice(0, length);\n }\n\n function clear(bytes32 key) internal {\n bytes32 lengthSlot = keccak256(abi.encodePacked(key, type(uint256).max));\n lengthSlot.tstore(uint256(0));\n }\n}\n" + }, + "src/misc/libraries/TransientStorageLib.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\n/// @title TransientStorageLib\nlibrary TransientStorageLib {\n function tstore(bytes32 slot, address value) internal {\n assembly (\"memory-safe\") {\n tstore(slot, value)\n }\n }\n\n function tstore(bytes32 slot, uint256 value) internal {\n assembly (\"memory-safe\") {\n tstore(slot, value)\n }\n }\n\n function tstore(bytes32 slot, bytes32 value) internal {\n assembly (\"memory-safe\") {\n tstore(slot, value)\n }\n }\n\n function tstore(bytes32 slot, bool value) internal {\n assembly (\"memory-safe\") {\n tstore(slot, value)\n }\n }\n\n function tloadAddress(bytes32 slot) internal view returns (address value) {\n assembly (\"memory-safe\") {\n value := tload(slot)\n }\n }\n\n function tloadUint128(bytes32 slot) internal view returns (uint128 value) {\n assembly (\"memory-safe\") {\n value := tload(slot)\n }\n }\n\n function tloadUint256(bytes32 slot) internal view returns (uint256 value) {\n assembly (\"memory-safe\") {\n value := tload(slot)\n }\n }\n\n function tloadBytes32(bytes32 slot) internal view returns (bytes32 value) {\n assembly (\"memory-safe\") {\n value := tload(slot)\n }\n }\n\n function tloadBool(bytes32 slot) internal view returns (bool value) {\n assembly (\"memory-safe\") {\n value := tload(slot)\n }\n }\n}\n" + }, + "src/misc/types/D18.sol": { + "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.28;\n\n// Small library to handle fixed point number operations with 18 decimals with static typing support.\n\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\n\ntype D18 is uint128;\n\nusing MathLib for uint256;\n\n/// @dev add two D18 types\nfunction add(D18 d1, D18 d2) pure returns (D18) {\n return D18.wrap(D18.unwrap(d1) + D18.unwrap(d2));\n}\n\n/// @dev substract two D18 types\nfunction sub(D18 d1, D18 d2) pure returns (D18) {\n return D18.wrap(D18.unwrap(d1) - D18.unwrap(d2));\n}\n\n/// @dev Divides one D18 by another one while retaining precision:\n/// - nominator (decimal): 50e18\n/// - denominator (decimal): 2e19\n/// - result (decimal): 25e17\nfunction divD18(D18 d1, D18 d2) pure returns (D18) {\n return D18.wrap(MathLib.mulDiv(D18.unwrap(d1), 1e18, D18.unwrap(d2)).toUint128());\n}\n\n/// @dev Multiplies one D18 with another one while retaining precision:\n/// - value1 (decimal): 50e18\n/// - value2 (decimal): 2e19\n/// - result (decimal): 100e19\nfunction mulD18(D18 d1, D18 d2) pure returns (D18) {\n return D18.wrap(MathLib.mulDiv(D18.unwrap(d1), D18.unwrap(d2), 1e18).toUint128());\n}\n\n/// @dev sugar for getting the inner representation of a D18\nfunction inner(D18 d1) pure returns (uint128) {\n return D18.unwrap(d1);\n}\n\n/// @dev Returns the reciprocal of a D18 decimal, i.e. 1 / d.\n/// Example: if d = 2.0 (2e18 internally), reciprocal(d) = 0.5 (5e17 internally).\nfunction reciprocal(D18 d) pure returns (D18) {\n uint128 val = D18.unwrap(d);\n require(val != 0, \"D18/division-by-zero\");\n return d18(1e18, val);\n}\n\n/// @dev Multiplies a decimal by an integer. i.e:\n/// - d (decimal): 1_500_000_000_000_000_000\n/// - value (integer): 4_000_000_000_000_000_000\n/// - result (integer): 6_000_000_000_000_000_000\nfunction mulUint128(D18 d, uint128 value, MathLib.Rounding rounding) pure returns (uint128) {\n return MathLib.mulDiv(D18.unwrap(d), value, 1e18, rounding).toUint128();\n}\n\n/// @dev Multiplies a decimal by an integer. i.e:\n/// - d (decimal): 1_500_000_000_000_000_000\n/// - value (integer): 4_000_000_000_000_000_000\n/// - result (integer): 6_000_000_000_000_000_000\nfunction mulUint256(D18 d, uint256 value, MathLib.Rounding rounding) pure returns (uint256) {\n return MathLib.mulDiv(D18.unwrap(d), value, 1e18, rounding);\n}\n\n/// @dev Divides an integer by a decimal, i.e.\n/// @dev Same as mulDiv for integers, i.e:\n/// - d (decimal): 2_000_000_000_000_000_000\n/// - value (integer): 100_000_000_000_000_000_000\n/// - result (integer): 50_000_000_000_000_000_000\nfunction reciprocalMulUint128(D18 d, uint128 value, MathLib.Rounding rounding) pure returns (uint128) {\n return MathLib.mulDiv(value, 1e18, d.inner(), rounding).toUint128();\n}\n\n/// @dev Divides an integer by a decimal, i.e.\n/// @dev Same as mulDiv for integers, i.e:\n/// - d (decimal): 2_000_000_000_000_000_000\n/// - value (integer): 100_000_000_000_000_000_000\n/// - result (integer): 50_000_000_000_000_000_000\nfunction reciprocalMulUint256(D18 d, uint256 value, MathLib.Rounding rounding) pure returns (uint256) {\n return MathLib.mulDiv(value, 1e18, d.inner(), rounding);\n}\n\n/// @dev Easy way to construct a decimal number\nfunction d18(uint128 value) pure returns (D18) {\n return D18.wrap(value);\n}\n\n/// @dev Easy way to construct a decimal number\nfunction d18(uint128 num, uint128 den) pure returns (D18) {\n return D18.wrap(MathLib.mulDiv(num, 1e18, den).toUint128());\n}\n\nfunction eq(D18 a, D18 b) pure returns (bool) {\n return D18.unwrap(a) == D18.unwrap(b);\n}\n\nfunction raw(D18 d) pure returns (uint128) {\n return D18.unwrap(d);\n}\n\nusing {\n add as +,\n sub as -,\n divD18 as /,\n inner,\n eq,\n mulD18 as *,\n mulUint128,\n mulUint256,\n reciprocalMulUint128,\n reciprocalMulUint256,\n reciprocal,\n raw\n} for D18 global;\n" + }, + "src/vaults/AsyncRequestManager.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\nimport {D18, d18} from \"src/misc/types/D18.sol\";\n\nimport {MessageLib} from \"src/common/libraries/MessageLib.sol\";\nimport {IVaultMessageSender} from \"src/common/interfaces/IGatewaySenders.sol\";\nimport {IRequestManagerGatewayHandler} from \"src/common/interfaces/IGatewayHandlers.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {PricingLib} from \"src/common/libraries/PricingLib.sol\";\n\nimport {IPoolManager, VaultDetails} from \"src/vaults/interfaces/IPoolManager.sol\";\nimport {IBalanceSheet} from \"src/vaults/interfaces/IBalanceSheet.sol\";\nimport {IAsyncRequestManager, AsyncInvestmentState} from \"src/vaults/interfaces/investments/IAsyncRequestManager.sol\";\nimport {IAsyncRedeemManager} from \"src/vaults/interfaces/investments/IAsyncRedeemManager.sol\";\nimport {IAsyncDepositManager} from \"src/vaults/interfaces/investments/IAsyncDepositManager.sol\";\nimport {IDepositManager} from \"src/vaults/interfaces/investments/IDepositManager.sol\";\nimport {IRedeemManager} from \"src/vaults/interfaces/investments/IRedeemManager.sol\";\nimport {IBaseRequestManager} from \"src/vaults/interfaces/investments/IBaseRequestManager.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\nimport {IAsyncVault, IBaseVault, IAsyncRedeemVault, VaultKind} from \"src/vaults/interfaces/IBaseVaults.sol\";\nimport {BaseRequestManager} from \"src/vaults/BaseRequestManager.sol\";\nimport {IPoolEscrowProvider} from \"src/vaults/interfaces/factories/IPoolEscrowFactory.sol\";\nimport {IEscrow} from \"src/vaults/interfaces/IEscrow.sol\";\nimport {ESCROW_HOOK_ID} from \"src/common/interfaces/IHook.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\n\n/// @title Investment Manager\n/// @notice This is the main contract vaults interact with for\n/// both incoming and outgoing investment transactions.\ncontract AsyncRequestManager is BaseRequestManager, IAsyncRequestManager {\n using CastLib for *;\n using MessageLib for *;\n using BytesLib for bytes;\n using MathLib for uint256;\n\n IVaultMessageSender public sender;\n IBalanceSheet public balanceSheet;\n\n mapping(IBaseVault vault => mapping(address investor => AsyncInvestmentState)) public investments;\n\n constructor(IEscrow globalEscrow_, address root_, address deployer)\n BaseRequestManager(globalEscrow_, root_, deployer)\n {}\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n function file(bytes32 what, address data) external override(IBaseRequestManager, BaseRequestManager) auth {\n if (what == \"sender\") sender = IVaultMessageSender(data);\n else if (what == \"poolManager\") poolManager = IPoolManager(data);\n else if (what == \"balanceSheet\") balanceSheet = IBalanceSheet(data);\n else if (what == \"poolEscrowProvider\") poolEscrowProvider = IPoolEscrowProvider(data);\n else revert FileUnrecognizedParam();\n emit File(what, data);\n }\n\n //----------------------------------------------------------------------------------------------\n // Async investment handlers\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IAsyncDepositManager\n function requestDeposit(IBaseVault vault_, uint256 assets, address controller, address, address)\n public\n auth\n returns (bool)\n {\n uint128 assets_ = assets.toUint128();\n require(assets_ != 0, ZeroAmountNotAllowed());\n\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n PoolId poolId = vault_.poolId();\n ShareClassId scId = vault_.scId();\n\n require(poolManager.isLinked(poolId, scId, vaultDetails.asset, vault_), AssetNotAllowed());\n\n require(_canTransfer(vault_, address(0), controller, convertToShares(vault_, assets_)), TransferNotAllowed());\n\n AsyncInvestmentState storage state = investments[vault_][controller];\n require(state.pendingCancelDepositRequest != true, CancellationIsPending());\n\n state.pendingDepositRequest += assets_;\n sender.sendDepositRequest(poolId, scId, controller.toBytes32(), vaultDetails.assetId, assets_);\n\n return true;\n }\n\n /// @inheritdoc IAsyncRedeemManager\n function requestRedeem(IBaseVault vault_, uint256 shares, address controller, address owner, address)\n public\n auth\n returns (bool)\n {\n uint128 shares_ = shares.toUint128();\n require(shares_ != 0, ZeroAmountNotAllowed());\n\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n PoolId poolId = vault_.poolId();\n ShareClassId scId = vault_.scId();\n\n require(poolManager.isLinked(poolId, scId, vaultDetails.asset, vault_), AssetNotAllowed());\n\n require(\n _canTransfer(vault_, owner, ESCROW_HOOK_ID, shares)\n && _canTransfer(vault_, controller, ESCROW_HOOK_ID, shares),\n TransferNotAllowed()\n );\n\n AsyncInvestmentState storage state = investments[vault_][controller];\n require(state.pendingCancelRedeemRequest != true, CancellationIsPending());\n\n state.pendingRedeemRequest = state.pendingRedeemRequest + shares_;\n sender.sendRedeemRequest(poolId, scId, controller.toBytes32(), vaultDetails.assetId, shares_);\n\n return true;\n }\n\n /// @inheritdoc IAsyncDepositManager\n function cancelDepositRequest(IBaseVault vault_, address controller, address) public auth {\n AsyncInvestmentState storage state = investments[vault_][controller];\n require(state.pendingDepositRequest > 0, NoPendingRequest());\n require(state.pendingCancelDepositRequest != true, CancellationIsPending());\n state.pendingCancelDepositRequest = true;\n\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n\n sender.sendCancelDepositRequest(vault_.poolId(), vault_.scId(), controller.toBytes32(), vaultDetails.assetId);\n }\n\n /// @inheritdoc IAsyncRedeemManager\n function cancelRedeemRequest(IBaseVault vault_, address controller, address) public auth {\n uint256 approximateSharesPayout = pendingRedeemRequest(vault_, controller);\n require(approximateSharesPayout > 0, NoPendingRequest());\n require(_canTransfer(vault_, address(0), controller, approximateSharesPayout), TransferNotAllowed());\n\n AsyncInvestmentState storage state = investments[vault_][controller];\n require(state.pendingCancelRedeemRequest != true, CancellationIsPending());\n state.pendingCancelRedeemRequest = true;\n\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n\n sender.sendCancelRedeemRequest(vault_.poolId(), vault_.scId(), controller.toBytes32(), vaultDetails.assetId);\n }\n\n //----------------------------------------------------------------------------------------------\n // Gateway handlers\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IRequestManagerGatewayHandler\n function approvedDeposits(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n uint128 assetAmount,\n D18 pricePoolPerAsset\n ) external auth {\n (address asset, uint256 tokenId) = poolManager.idToAsset(assetId);\n\n // Note deposit and transfer from global escrow into the pool escrow,\n // to make assets available for managers of the balance sheet\n balanceSheet.overridePricePoolPerAsset(poolId, scId, assetId, pricePoolPerAsset);\n balanceSheet.noteDeposit(poolId, scId, asset, tokenId, address(globalEscrow), assetAmount);\n\n address poolEscrow = address(poolEscrowProvider.escrow(poolId));\n globalEscrow.authTransferTo(asset, tokenId, poolEscrow, assetAmount);\n }\n\n /// @inheritdoc IRequestManagerGatewayHandler\n function issuedShares(PoolId poolId, ShareClassId scId, uint128 shareAmount, D18 pricePoolPerShare) external auth {\n balanceSheet.overridePricePoolPerShare(poolId, scId, pricePoolPerShare);\n balanceSheet.issue(poolId, scId, address(globalEscrow), shareAmount);\n }\n\n /// @inheritdoc IRequestManagerGatewayHandler\n function revokedShares(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n uint128 assetAmount,\n uint128 shareAmount,\n D18 pricePoolPerShare\n ) external auth {\n // Lock assets to ensure they are not withdrawn and are available for the redeeming user\n (address asset, uint256 tokenId) = poolManager.idToAsset(assetId);\n poolEscrowProvider.escrow(poolId).reserveIncrease(scId, asset, tokenId, assetAmount);\n\n balanceSheet.overridePricePoolPerShare(poolId, scId, pricePoolPerShare);\n balanceSheet.revoke(poolId, scId, address(globalEscrow), shareAmount);\n }\n\n /// @inheritdoc IRequestManagerGatewayHandler\n function fulfillDepositRequest(\n PoolId poolId,\n ShareClassId scId,\n address user,\n AssetId assetId,\n uint128 assets,\n uint128 shares\n ) public auth {\n IAsyncVault vault_ = IAsyncVault(address(vault[poolId][scId][assetId]));\n\n AsyncInvestmentState storage state = investments[vault_][user];\n require(state.pendingDepositRequest != 0, NoPendingRequest());\n state.depositPrice = _calculatePriceAssetPerShare(\n vault_, state.maxMint + shares, _maxDeposit(vault_, user) + assets, MathLib.Rounding.Down\n );\n state.maxMint = state.maxMint + shares;\n state.pendingDepositRequest = state.pendingDepositRequest > assets ? state.pendingDepositRequest - assets : 0;\n\n if (state.pendingDepositRequest == 0) delete state.pendingCancelDepositRequest;\n\n vault_.onDepositClaimable(user, assets, shares);\n }\n\n /// @inheritdoc IRequestManagerGatewayHandler\n function fulfillRedeemRequest(\n PoolId poolId,\n ShareClassId scId,\n address user,\n AssetId assetId,\n uint128 assets,\n uint128 shares\n ) public auth {\n IAsyncRedeemVault vault_ = IAsyncRedeemVault(address(vault[poolId][scId][assetId]));\n\n AsyncInvestmentState storage state = investments[vault_][user];\n require(state.pendingRedeemRequest != 0, NoPendingRequest());\n\n // Calculate new weighted average redeem price and update order book values\n state.redeemPrice = _calculatePriceAssetPerShare(\n vault_, ((maxRedeem(vault_, user)) + shares).toUint128(), state.maxWithdraw + assets, MathLib.Rounding.Down\n );\n state.maxWithdraw = state.maxWithdraw + assets;\n state.pendingRedeemRequest = state.pendingRedeemRequest > shares ? state.pendingRedeemRequest - shares : 0;\n\n if (state.pendingRedeemRequest == 0) delete state.pendingCancelRedeemRequest;\n\n vault_.onRedeemClaimable(user, assets, shares);\n }\n\n /// @inheritdoc IRequestManagerGatewayHandler\n function fulfillCancelDepositRequest(\n PoolId poolId,\n ShareClassId scId,\n address user,\n AssetId assetId,\n uint128 assets,\n uint128 fulfillment\n ) public auth {\n IAsyncVault vault_ = IAsyncVault(address(vault[poolId][scId][assetId]));\n\n AsyncInvestmentState storage state = investments[vault_][user];\n require(state.pendingCancelDepositRequest == true, NoPendingRequest());\n\n state.claimableCancelDepositRequest = state.claimableCancelDepositRequest + assets;\n state.pendingDepositRequest =\n state.pendingDepositRequest > fulfillment ? state.pendingDepositRequest - fulfillment : 0;\n\n if (state.pendingDepositRequest == 0) delete state.pendingCancelDepositRequest;\n\n vault_.onCancelDepositClaimable(user, assets);\n }\n\n /// @inheritdoc IRequestManagerGatewayHandler\n function fulfillCancelRedeemRequest(PoolId poolId, ShareClassId scId, address user, AssetId assetId, uint128 shares)\n public\n auth\n {\n IAsyncRedeemVault vault_ = IAsyncRedeemVault(address(vault[poolId][scId][assetId]));\n AsyncInvestmentState storage state = investments[vault_][user];\n require(state.pendingCancelRedeemRequest == true, NoPendingRequest());\n\n state.claimableCancelRedeemRequest = state.claimableCancelRedeemRequest + shares;\n state.pendingRedeemRequest = state.pendingRedeemRequest > shares ? state.pendingRedeemRequest - shares : 0;\n\n if (state.pendingRedeemRequest == 0) delete state.pendingCancelRedeemRequest;\n\n vault_.onCancelRedeemClaimable(user, shares);\n }\n\n //----------------------------------------------------------------------------------------------\n // Sync investment handlers\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IDepositManager\n function deposit(IBaseVault vault_, uint256 assets, address receiver, address controller)\n public\n auth\n returns (uint256 shares)\n {\n require(assets <= _maxDeposit(vault_, controller), ExceedsMaxDeposit());\n\n AsyncInvestmentState storage state = investments[vault_][controller];\n\n uint128 sharesUp = _assetToShareAmount(vault_, assets.toUint128(), state.depositPrice, MathLib.Rounding.Up);\n uint128 sharesDown = _assetToShareAmount(vault_, assets.toUint128(), state.depositPrice, MathLib.Rounding.Down);\n shares = uint256(sharesDown);\n _processDeposit(state, sharesUp, sharesDown, vault_, receiver);\n }\n\n /// @inheritdoc IDepositManager\n function mint(IBaseVault vault_, uint256 shares, address receiver, address controller)\n public\n auth\n returns (uint256 assets)\n {\n AsyncInvestmentState storage state = investments[vault_][controller];\n uint128 shares_ = shares.toUint128();\n\n assets = uint256(_shareToAssetAmount(vault_, shares_, state.depositPrice, MathLib.Rounding.Up));\n _processDeposit(state, shares_, shares_, vault_, receiver);\n }\n\n function _processDeposit(\n AsyncInvestmentState storage state,\n uint128 sharesUp,\n uint128 sharesDown,\n IBaseVault vault_,\n address receiver\n ) internal {\n require(sharesUp <= state.maxMint, ExceedsDepositLimits());\n state.maxMint = state.maxMint > sharesUp ? state.maxMint - sharesUp : 0;\n\n if (sharesDown > 0) {\n globalEscrow.authTransferTo(vault_.share(), receiver, sharesDown);\n }\n }\n\n /// @inheritdoc IRedeemManager\n function redeem(IBaseVault vault_, uint256 shares, address receiver, address controller)\n public\n auth\n returns (uint256 assets)\n {\n require(shares <= maxRedeem(vault_, controller), ExceedsMaxRedeem());\n\n AsyncInvestmentState storage state = investments[vault_][controller];\n\n uint128 assetsUp = _shareToAssetAmount(vault_, shares.toUint128(), state.redeemPrice, MathLib.Rounding.Up);\n uint128 assetsDown = _shareToAssetAmount(vault_, shares.toUint128(), state.redeemPrice, MathLib.Rounding.Down);\n _processRedeem(state, assetsUp, assetsDown, vault_, receiver, controller);\n assets = uint256(assetsDown);\n }\n\n /// @inheritdoc IRedeemManager\n function withdraw(IBaseVault vault_, uint256 assets, address receiver, address controller)\n public\n auth\n returns (uint256 shares)\n {\n AsyncInvestmentState storage state = investments[vault_][controller];\n uint128 assets_ = assets.toUint128();\n _processRedeem(state, assets_, assets_, vault_, receiver, controller);\n\n shares = uint256(_assetToShareAmount(vault_, assets_, state.redeemPrice, MathLib.Rounding.Up));\n }\n\n function _processRedeem(\n AsyncInvestmentState storage state,\n uint128 assetsUp,\n uint128 assetsDown,\n IBaseVault vault_,\n address receiver,\n address controller\n ) internal {\n if (controller != receiver) {\n require(\n _canTransfer(vault_, controller, receiver, convertToShares(vault_, assetsDown)), TransferNotAllowed()\n );\n }\n\n require(_canTransfer(vault_, receiver, address(0), convertToShares(vault_, assetsDown)), TransferNotAllowed());\n\n require(assetsUp <= state.maxWithdraw, ExceedsRedeemLimits());\n state.maxWithdraw = state.maxWithdraw > assetsUp ? state.maxWithdraw - assetsUp : 0;\n\n if (assetsDown > 0) {\n _withdraw(vault_, receiver, assetsDown);\n }\n }\n\n /// @dev Transfer funds from escrow to receiver and update holdings\n function _withdraw(IBaseVault vault_, address receiver, uint128 assets) internal {\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n\n PoolId poolId = vault_.poolId();\n ShareClassId scId = vault_.scId();\n\n poolEscrowProvider.escrow(poolId).reserveDecrease(scId, vaultDetails.asset, vaultDetails.tokenId, assets);\n balanceSheet.withdraw(poolId, scId, vaultDetails.asset, vaultDetails.tokenId, receiver, assets);\n }\n\n //----------------------------------------------------------------------------------------------\n // Cancellation claim handlers\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IAsyncDepositManager\n function claimCancelDepositRequest(IBaseVault vault_, address receiver, address controller)\n public\n auth\n returns (uint256 assets)\n {\n AsyncInvestmentState storage state = investments[vault_][controller];\n assets = state.claimableCancelDepositRequest;\n state.claimableCancelDepositRequest = 0;\n uint256 shares = convertToShares(vault_, assets);\n\n if (controller != receiver) {\n require(_canTransfer(vault_, controller, receiver, shares), TransferNotAllowed());\n }\n require(_canTransfer(vault_, receiver, address(0), shares), TransferNotAllowed());\n\n if (assets > 0) {\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n globalEscrow.authTransferTo(vaultDetails.asset, vaultDetails.tokenId, receiver, assets);\n }\n }\n\n /// @inheritdoc IAsyncRedeemManager\n function claimCancelRedeemRequest(IBaseVault vault_, address receiver, address controller)\n public\n auth\n returns (uint256 shares)\n {\n AsyncInvestmentState storage state = investments[vault_][controller];\n shares = state.claimableCancelRedeemRequest;\n state.claimableCancelRedeemRequest = 0;\n\n if (shares > 0) {\n globalEscrow.authTransferTo(vault_.share(), receiver, shares);\n }\n }\n\n //----------------------------------------------------------------------------------------------\n // View methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IDepositManager\n function maxDeposit(IBaseVault vault_, address user) public view returns (uint256 assets) {\n if (!_canTransfer(vault_, ESCROW_HOOK_ID, user, 0)) {\n return 0;\n }\n assets = uint256(_maxDeposit(vault_, user));\n }\n\n function _maxDeposit(IBaseVault vault_, address user) internal view returns (uint128 assets) {\n AsyncInvestmentState memory state = investments[vault_][user];\n\n assets = _shareToAssetAmount(vault_, state.maxMint, state.depositPrice, MathLib.Rounding.Down);\n }\n\n /// @inheritdoc IDepositManager\n function maxMint(IBaseVault vault_, address user) public view returns (uint256 shares) {\n if (!_canTransfer(vault_, ESCROW_HOOK_ID, user, 0)) {\n return 0;\n }\n shares = uint256(investments[vault_][user].maxMint);\n }\n\n /// @inheritdoc IRedeemManager\n function maxWithdraw(IBaseVault vault_, address user) public view returns (uint256 assets) {\n if (!_canTransfer(vault_, user, address(0), 0)) return 0;\n assets = uint256(investments[vault_][user].maxWithdraw);\n }\n\n /// @inheritdoc IRedeemManager\n function maxRedeem(IBaseVault vault_, address user) public view returns (uint256 shares) {\n if (!_canTransfer(vault_, user, address(0), 0)) return 0;\n AsyncInvestmentState memory state = investments[vault_][user];\n\n shares = uint256(_assetToShareAmount(vault_, state.maxWithdraw, state.redeemPrice, MathLib.Rounding.Down));\n }\n\n /// @inheritdoc IAsyncDepositManager\n function pendingDepositRequest(IBaseVault vault_, address user) public view returns (uint256 assets) {\n assets = uint256(investments[vault_][user].pendingDepositRequest);\n }\n\n /// @inheritdoc IAsyncRedeemManager\n function pendingRedeemRequest(IBaseVault vault_, address user) public view returns (uint256 shares) {\n shares = uint256(investments[vault_][user].pendingRedeemRequest);\n }\n\n /// @inheritdoc IAsyncDepositManager\n function pendingCancelDepositRequest(IBaseVault vault_, address user) public view returns (bool isPending) {\n isPending = investments[vault_][user].pendingCancelDepositRequest;\n }\n\n /// @inheritdoc IAsyncRedeemManager\n function pendingCancelRedeemRequest(IBaseVault vault_, address user) public view returns (bool isPending) {\n isPending = investments[vault_][user].pendingCancelRedeemRequest;\n }\n\n /// @inheritdoc IAsyncDepositManager\n function claimableCancelDepositRequest(IBaseVault vault_, address user) public view returns (uint256 assets) {\n assets = investments[vault_][user].claimableCancelDepositRequest;\n }\n\n /// @inheritdoc IAsyncRedeemManager\n function claimableCancelRedeemRequest(IBaseVault vault_, address user) public view returns (uint256 shares) {\n shares = investments[vault_][user].claimableCancelRedeemRequest;\n }\n\n //----------------------------------------------------------------------------------------------\n // Helpers\n //----------------------------------------------------------------------------------------------\n\n /// @dev Checks transfer restrictions for the vault shares. Sender (from) and receiver (to) have to both pass\n /// the restrictions for a successful share transfer.\n function _canTransfer(IBaseVault vault_, address from, address to, uint256 value) internal view returns (bool) {\n IShareToken share = IShareToken(vault_.share());\n return share.checkTransferRestriction(from, to, value);\n }\n\n function _assetToShareAmount(\n IBaseVault vault_,\n uint128 assets,\n uint256 priceAssetPerShare,\n MathLib.Rounding rounding\n ) internal view returns (uint128 shares) {\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n address shareToken = vault_.share();\n\n return PricingLib.assetToShareAmount(\n shareToken, vaultDetails.asset, vaultDetails.tokenId, assets, d18(priceAssetPerShare.toUint128()), rounding\n );\n }\n\n function _shareToAssetAmount(\n IBaseVault vault_,\n uint128 shares,\n uint256 priceAssetPerShare,\n MathLib.Rounding rounding\n ) internal view returns (uint128 assets) {\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n address shareToken = vault_.share();\n\n return PricingLib.shareToAssetAmount(\n shareToken, shares, vaultDetails.asset, vaultDetails.tokenId, d18(priceAssetPerShare.toUint128()), rounding\n );\n }\n\n function _calculatePriceAssetPerShare(IBaseVault vault_, uint128 shares, uint128 assets, MathLib.Rounding rounding)\n internal\n view\n returns (uint256 price)\n {\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n address shareToken = vault_.share();\n\n return PricingLib.calculatePriceAssetPerShare(\n shareToken, shares, vaultDetails.asset, vaultDetails.tokenId, assets, rounding\n );\n }\n}\n" + }, + "src/vaults/AsyncVault.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport \"src/misc/interfaces/IERC7540.sol\";\nimport \"src/misc/interfaces/IERC7575.sol\";\nimport {SafeTransferLib} from \"src/misc/libraries/SafeTransferLib.sol\";\nimport {IERC20} from \"src/misc/interfaces/IERC20.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nimport {IAsyncRedeemVault, VaultKind} from \"src/vaults/interfaces/IBaseVaults.sol\";\nimport {BaseVault, BaseAsyncRedeemVault} from \"src/vaults/BaseVaults.sol\";\nimport {IAsyncVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\nimport {IAsyncRequestManager} from \"src/vaults/interfaces/investments/IAsyncRequestManager.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\n\n/// @title AsyncVault\n/// @notice Asynchronous Tokenized Vault standard implementation for Centrifuge pools\n///\n/// @dev Each vault issues shares of Centrifuge share class tokens as restricted ERC-20 tokens\n/// against asset deposits based on the current share price.\n///\n/// ERC-7540 is an extension of the ERC-4626 standard by 'requestDeposit' & 'requestRedeem' methods, where\n/// deposit and redeem orders are submitted to the pools to be included in the execution of the following epoch.\n/// After execution users can use the deposit, mint, redeem and withdraw functions to get their shares\n/// and/or assets from the pools.\ncontract AsyncVault is BaseAsyncRedeemVault, IAsyncVault {\n constructor(\n PoolId poolId_,\n ShareClassId scId_,\n address asset_,\n IShareToken token_,\n address root_,\n IAsyncRequestManager manager_\n ) BaseVault(poolId_, scId_, asset_, token_, root_, manager_) BaseAsyncRedeemVault(manager_) {}\n\n //----------------------------------------------------------------------------------------------\n // ERC-7540 deposit\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC7540Deposit\n function requestDeposit(uint256 assets, address controller, address owner) public returns (uint256) {\n require(owner == msg.sender || isOperator[owner][msg.sender], InvalidOwner());\n require(IERC20(asset).balanceOf(owner) >= assets, InsufficientBalance());\n\n require(asyncManager().requestDeposit(this, assets, controller, owner, msg.sender), RequestDepositFailed());\n SafeTransferLib.safeTransferFrom(asset, owner, address(manager.globalEscrow()), assets);\n\n emit DepositRequest(controller, owner, REQUEST_ID, msg.sender, assets);\n return REQUEST_ID;\n }\n\n /// @inheritdoc IERC7540Deposit\n function pendingDepositRequest(uint256, address controller) public view returns (uint256 pendingAssets) {\n pendingAssets = asyncManager().pendingDepositRequest(this, controller);\n }\n\n /// @inheritdoc IERC7540Deposit\n function claimableDepositRequest(uint256, address controller) external view returns (uint256 claimableAssets) {\n claimableAssets = maxDeposit(controller);\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-7887\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC7887Deposit\n function cancelDepositRequest(uint256, address controller) external {\n _validateController(controller);\n asyncManager().cancelDepositRequest(this, controller, msg.sender);\n emit CancelDepositRequest(controller, REQUEST_ID, msg.sender);\n }\n\n /// @inheritdoc IERC7887Deposit\n function pendingCancelDepositRequest(uint256, address controller) public view returns (bool isPending) {\n isPending = asyncManager().pendingCancelDepositRequest(this, controller);\n }\n\n /// @inheritdoc IERC7887Deposit\n function claimableCancelDepositRequest(uint256, address controller) public view returns (uint256 claimableAssets) {\n claimableAssets = asyncManager().claimableCancelDepositRequest(this, controller);\n }\n\n /// @inheritdoc IERC7887Deposit\n function claimCancelDepositRequest(uint256, address receiver, address controller)\n external\n returns (uint256 assets)\n {\n _validateController(controller);\n assets = asyncManager().claimCancelDepositRequest(this, receiver, controller);\n emit CancelDepositClaim(controller, receiver, REQUEST_ID, msg.sender, assets);\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-165\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC165\n function supportsInterface(bytes4 interfaceId) public pure override(BaseAsyncRedeemVault, IERC165) returns (bool) {\n return interfaceId == type(IERC7540Deposit).interfaceId || interfaceId == type(IERC7887Deposit).interfaceId\n || super.supportsInterface(interfaceId);\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-7540 claim\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC7575\n function maxDeposit(address controller) public view returns (uint256 maxAssets) {\n maxAssets = asyncManager().maxDeposit(this, controller);\n }\n\n /// @inheritdoc IERC7540Deposit\n function deposit(uint256 assets, address receiver, address controller) public returns (uint256 shares) {\n _validateController(controller);\n shares = asyncManager().deposit(this, assets, receiver, controller);\n emit Deposit(controller, receiver, assets, shares);\n }\n\n /// @inheritdoc IERC7575\n /// @notice When claiming deposit requests using deposit(), there can be some precision loss leading to dust.\n /// It is recommended to use mint() to claim deposit requests instead.\n function deposit(uint256 assets, address receiver) external returns (uint256 shares) {\n shares = deposit(assets, receiver, msg.sender);\n }\n\n /// @inheritdoc IERC7575\n function maxMint(address controller) public view returns (uint256 maxShares) {\n maxShares = asyncManager().maxMint(this, controller);\n }\n\n /// @inheritdoc IERC7540Deposit\n function mint(uint256 shares, address receiver, address controller) public returns (uint256 assets) {\n _validateController(controller);\n assets = asyncManager().mint(this, shares, receiver, controller);\n emit Deposit(controller, receiver, assets, shares);\n }\n\n /// @inheritdoc IERC7575\n function mint(uint256 shares, address receiver) public returns (uint256 assets) {\n assets = mint(shares, receiver, msg.sender);\n }\n\n /// @dev Strongly-typed accessor to the generic async redeem manager\n function asyncManager() public view returns (IAsyncRequestManager) {\n return IAsyncRequestManager(address(IAsyncRedeemVault(this).asyncRedeemManager()));\n }\n\n /// @dev Preview functions for ERC-7540 vaults revert\n function previewDeposit(uint256) external pure returns (uint256) {\n revert();\n }\n\n /// @dev Preview functions for ERC-7540 vaults revert\n function previewMint(uint256) external pure returns (uint256) {\n revert();\n }\n\n //----------------------------------------------------------------------------------------------\n // Event emitters\n //----------------------------------------------------------------------------------------------\n\n function onDepositClaimable(address controller, uint256 assets, uint256 shares) public virtual auth {\n emit DepositClaimable(controller, REQUEST_ID, assets, shares);\n }\n\n function onCancelDepositClaimable(address controller, uint256 assets) public virtual auth {\n emit CancelDepositClaimable(controller, REQUEST_ID, assets);\n }\n\n //----------------------------------------------------------------------------------------------\n // IBaseVault view\n //----------------------------------------------------------------------------------------------\n\n function vaultKind() public pure returns (VaultKind vaultKind_) {\n return VaultKind.Async;\n }\n}\n" + }, + "src/vaults/BalanceSheet.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {IAuth} from \"src/misc/interfaces/IAuth.sol\";\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {D18, d18} from \"src/misc/types/D18.sol\";\nimport {IERC6909} from \"src/misc/interfaces/IERC6909.sol\";\nimport {Recoverable} from \"src/misc/Recoverable.sol\";\nimport {SafeTransferLib} from \"src/misc/libraries/SafeTransferLib.sol\";\nimport {TransientStorageLib} from \"src/misc/libraries/TransientStorageLib.sol\";\n\nimport {IRoot} from \"src/common/interfaces/IRoot.sol\";\nimport {IGateway} from \"src/common/interfaces/IGateway.sol\";\nimport {MessageLib, UpdateContractType} from \"src/common/libraries/MessageLib.sol\";\nimport {IVaultMessageSender} from \"../common/interfaces/IGatewaySenders.sol\";\nimport {IBalanceSheetGatewayHandler} from \"src/common/interfaces/IGatewayHandlers.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\n\nimport {IPoolManager} from \"src/vaults/interfaces/IPoolManager.sol\";\nimport {IBalanceSheet, QueueAmount} from \"src/vaults/interfaces/IBalanceSheet.sol\";\nimport {IPoolEscrow} from \"src/vaults/interfaces/IEscrow.sol\";\nimport {IUpdateContract} from \"src/vaults/interfaces/IUpdateContract.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\nimport {IPoolEscrowProvider} from \"src/vaults/interfaces/factories/IPoolEscrowFactory.sol\";\n\n/// @title Balance Sheet\n/// @notice Management contract that integrates all balance sheet functions of a pool:\n/// - Issuing and revoking shares\n/// - Depositing and withdrawing assets\n/// - Force transferring shares\n///\n/// Share and asset updates to the Hub are optionally queued, to reduce the cost\n/// per transaction. Dequeuing can be triggered locally by the manager or from the Hub.\ncontract BalanceSheet is Auth, Recoverable, IBalanceSheet, IBalanceSheetGatewayHandler, IUpdateContract {\n using MathLib for *;\n using CastLib for bytes32;\n\n IRoot public immutable root;\n\n IPoolManager public poolManager;\n IVaultMessageSender public sender;\n IPoolEscrowProvider public poolEscrowProvider;\n\n mapping(PoolId => mapping(address => bool)) public manager;\n mapping(PoolId poolId => mapping(ShareClassId scId => bool)) public queueEnabled;\n mapping(PoolId poolId => mapping(ShareClassId scId => QueueAmount)) public queuedShares;\n mapping(PoolId poolId => mapping(ShareClassId scId => mapping(AssetId assetId => QueueAmount))) public queuedAssets;\n\n constructor(IRoot root_, address deployer) Auth(deployer) {\n root = root_;\n }\n\n /// @dev Check if the msg.sender is ward or a manager\n modifier authOrManager(PoolId poolId) {\n require(wards[msg.sender] == 1 || manager[poolId][msg.sender], IAuth.NotAuthorized());\n _;\n }\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n function file(bytes32 what, address data) external auth {\n if (what == \"poolManager\") poolManager = IPoolManager(data);\n else if (what == \"sender\") sender = IVaultMessageSender(data);\n else if (what == \"poolEscrowProvider\") poolEscrowProvider = IPoolEscrowProvider(data);\n else revert FileUnrecognizedParam();\n emit File(what, data);\n }\n\n function update(PoolId poolId, ShareClassId, /* scId */ bytes calldata payload) external auth {\n uint8 kind = uint8(MessageLib.updateContractType(payload));\n\n if (kind == uint8(UpdateContractType.UpdateManager)) {\n MessageLib.UpdateContractUpdateManager memory m = MessageLib.deserializeUpdateContractUpdateManager(payload);\n address who = m.who.toAddress();\n\n manager[poolId][who] = m.canManage;\n emit UpdateManager(poolId, who, m.canManage);\n } else {\n revert UnknownUpdateContractType();\n }\n }\n\n //----------------------------------------------------------------------------------------------\n // Management functions\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IBalanceSheet\n function deposit(PoolId poolId, ShareClassId scId, address asset, uint256 tokenId, address owner, uint128 amount)\n external\n authOrManager(poolId)\n {\n AssetId assetId = poolManager.assetToId(asset, tokenId);\n _noteDeposit(poolId, scId, assetId, asset, tokenId, owner, amount);\n _executeDeposit(poolId, asset, tokenId, owner, amount);\n }\n\n /// @inheritdoc IBalanceSheet\n /// @dev This function is mostly useful to keep higher level integrations CEI adherent.\n function noteDeposit(\n PoolId poolId,\n ShareClassId scId,\n address asset,\n uint256 tokenId,\n address owner,\n uint128 amount\n ) external authOrManager(poolId) {\n AssetId assetId = poolManager.assetToId(asset, tokenId);\n _noteDeposit(poolId, scId, assetId, asset, tokenId, owner, amount);\n }\n\n /// @inheritdoc IBalanceSheet\n function withdraw(\n PoolId poolId,\n ShareClassId scId,\n address asset,\n uint256 tokenId,\n address receiver,\n uint128 amount\n ) external authOrManager(poolId) {\n AssetId assetId = poolManager.assetToId(asset, tokenId);\n _withdraw(poolId, scId, assetId, asset, tokenId, receiver, amount);\n }\n\n /// @inheritdoc IBalanceSheet\n function issue(PoolId poolId, ShareClassId scId, address to, uint128 shares) external authOrManager(poolId) {\n _issue(poolId, scId, to, shares);\n }\n\n /// @inheritdoc IBalanceSheet\n function revoke(PoolId poolId, ShareClassId scId, address from, uint128 shares) external authOrManager(poolId) {\n _noteRevoke(poolId, scId, from, shares);\n _executeRevoke(poolId, scId, from, shares);\n }\n\n /// @inheritdoc IBalanceSheet\n /// @dev This function is mostly useful to keep higher level integrations CEI adherent.\n function noteRevoke(PoolId poolId, ShareClassId scId, address from, uint128 shares)\n external\n authOrManager(poolId)\n {\n _noteRevoke(poolId, scId, from, shares);\n }\n\n /// @inheritdoc IBalanceSheet\n function transferSharesFrom(PoolId poolId, ShareClassId scId, address from, address to, uint256 amount)\n external\n authOrManager(poolId)\n {\n require(!root.endorsed(from), CannotTransferFromEndorsedContract());\n IShareToken token = IShareToken(poolManager.shareToken(poolId, scId));\n token.authTransferFrom(from, from, to, amount);\n }\n\n /// @inheritdoc IBalanceSheet\n function overridePricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId, D18 value)\n external\n authOrManager(poolId)\n {\n TransientStorageLib.tstore(keccak256(abi.encode(\"pricePoolPerAsset\", poolId, scId, assetId)), value.raw());\n TransientStorageLib.tstore(keccak256(abi.encode(\"pricePoolPerAssetIsSet\", poolId, scId, assetId)), true);\n }\n\n /// @inheritdoc IBalanceSheet\n function overridePricePoolPerShare(PoolId poolId, ShareClassId scId, D18 value) external authOrManager(poolId) {\n TransientStorageLib.tstore(keccak256(abi.encode(\"pricePoolPerShare\", poolId, scId)), value.raw());\n TransientStorageLib.tstore(keccak256(abi.encode(\"pricePoolPerShareIsSet\", poolId, scId)), true);\n }\n\n //----------------------------------------------------------------------------------------------\n // Gateway handlers\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IBalanceSheetGatewayHandler\n function triggerDeposit(PoolId poolId, ShareClassId scId, AssetId assetId, address owner, uint128 amount)\n external\n auth\n {\n (address asset, uint256 tokenId) = poolManager.idToAsset(assetId);\n _noteDeposit(poolId, scId, assetId, asset, tokenId, owner, amount);\n _executeDeposit(poolId, asset, tokenId, owner, amount);\n }\n\n /// @inheritdoc IBalanceSheetGatewayHandler\n function triggerWithdraw(PoolId poolId, ShareClassId scId, AssetId assetId, address receiver, uint128 amount)\n external\n auth\n {\n (address asset, uint256 tokenId) = poolManager.idToAsset(assetId);\n _withdraw(poolId, scId, assetId, asset, tokenId, receiver, amount);\n }\n\n /// @inheritdoc IBalanceSheetGatewayHandler\n function triggerIssueShares(PoolId poolId, ShareClassId scId, address receiver, uint128 shares) external auth {\n _issue(poolId, scId, receiver, shares);\n }\n\n /// @inheritdoc IBalanceSheetGatewayHandler\n function setQueue(PoolId poolId, ShareClassId scId, bool enabled) external auth {\n queueEnabled[poolId][scId] = enabled;\n }\n\n /// @inheritdoc IBalanceSheetGatewayHandler\n function submitQueuedAssets(PoolId poolId, ShareClassId scId, AssetId assetId) external authOrManager(poolId) {\n _submitQueuedAssets(poolId, scId, assetId);\n }\n\n /// @inheritdoc IBalanceSheetGatewayHandler\n function submitQueuedShares(PoolId poolId, ShareClassId scId) external authOrManager(poolId) {\n _submitQueuedShares(poolId, scId);\n }\n\n //----------------------------------------------------------------------------------------------\n // Internal\n //----------------------------------------------------------------------------------------------\n\n function _noteDeposit(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n address asset,\n uint256 tokenId,\n address owner,\n uint128 amount\n ) internal {\n IPoolEscrow escrow = poolEscrowProvider.escrow(poolId);\n escrow.deposit(scId, asset, tokenId, amount);\n\n D18 pricePoolPerAsset_ = _pricePoolPerAsset(poolId, scId, assetId);\n emit Deposit(poolId, scId, asset, tokenId, owner, amount, pricePoolPerAsset_);\n\n if (queueEnabled[poolId][scId]) {\n queuedAssets[poolId][scId][assetId].increase += amount;\n } else {\n sender.sendUpdateHoldingAmount(poolId, scId, assetId, owner, amount, pricePoolPerAsset_, true);\n }\n }\n\n function _executeDeposit(PoolId poolId, address asset, uint256 tokenId, address owner, uint128 amount) internal {\n IPoolEscrow escrow = poolEscrowProvider.escrow(poolId);\n if (tokenId == 0) {\n SafeTransferLib.safeTransferFrom(asset, owner, address(escrow), amount);\n } else {\n IERC6909(asset).transferFrom(owner, address(escrow), tokenId, amount);\n }\n }\n\n function _withdraw(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n address asset,\n uint256 tokenId,\n address receiver,\n uint128 amount\n ) internal {\n IPoolEscrow escrow = poolEscrowProvider.escrow(poolId);\n escrow.withdraw(scId, asset, tokenId, amount);\n\n D18 pricePoolPerAsset_ = _pricePoolPerAsset(poolId, scId, assetId);\n emit Withdraw(poolId, scId, asset, tokenId, receiver, amount, pricePoolPerAsset_);\n\n if (queueEnabled[poolId][scId]) {\n queuedAssets[poolId][scId][assetId].decrease += amount;\n } else {\n sender.sendUpdateHoldingAmount(poolId, scId, assetId, receiver, amount, pricePoolPerAsset_, false);\n }\n\n escrow.authTransferTo(asset, tokenId, receiver, amount);\n }\n\n function _issue(PoolId poolId, ShareClassId scId, address to, uint128 shares) internal {\n emit Issue(poolId, scId, to, _pricePoolPerShare(poolId, scId), shares);\n\n if (queueEnabled[poolId][scId]) {\n queuedShares[poolId][scId].increase += shares;\n } else {\n sender.sendUpdateShares(poolId, scId, shares, true);\n }\n\n IShareToken token = poolManager.shareToken(poolId, scId);\n token.mint(to, shares);\n }\n\n function _noteRevoke(PoolId poolId, ShareClassId scId, address from, uint128 shares) internal {\n emit Revoke(poolId, scId, from, _pricePoolPerShare(poolId, scId), shares);\n\n if (queueEnabled[poolId][scId]) {\n queuedShares[poolId][scId].decrease += shares;\n } else {\n sender.sendUpdateShares(poolId, scId, shares, false);\n }\n }\n\n function _executeRevoke(PoolId poolId, ShareClassId scId, address from, uint128 shares) internal {\n IShareToken token = poolManager.shareToken(poolId, scId);\n token.authTransferFrom(from, from, address(this), shares);\n token.burn(address(this), shares);\n }\n\n function _submitQueuedShares(PoolId poolId, ShareClassId scId) internal {\n QueueAmount storage queue = queuedShares[poolId][scId];\n\n if (queue.increase > queue.decrease) {\n sender.sendUpdateShares(poolId, scId, queue.increase - queue.decrease, true);\n } else if (queue.decrease > queue.increase) {\n sender.sendUpdateShares(poolId, scId, queue.decrease - queue.increase, false);\n }\n\n queue.increase = 0;\n queue.decrease = 0;\n }\n\n function _submitQueuedAssets(PoolId poolId, ShareClassId scId, AssetId assetId) internal {\n QueueAmount storage queue = queuedAssets[poolId][scId][assetId];\n\n D18 pricePoolPerAsset = _pricePoolPerAsset(poolId, scId, assetId);\n if (queue.increase > queue.decrease) {\n sender.sendUpdateHoldingAmount(\n poolId, scId, assetId, address(0), queue.increase - queue.decrease, pricePoolPerAsset, true\n );\n } else if (queue.decrease > queue.increase) {\n sender.sendUpdateHoldingAmount(\n poolId, scId, assetId, address(0), queue.decrease - queue.increase, pricePoolPerAsset, false\n );\n }\n\n queue.increase = 0;\n queue.decrease = 0;\n }\n\n function _pricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId) internal view returns (D18) {\n if (TransientStorageLib.tloadBool(keccak256(abi.encode(\"pricePoolPerAssetIsSet\", poolId, scId, assetId)))) {\n return\n d18(TransientStorageLib.tloadUint128(keccak256(abi.encode(\"pricePoolPerAsset\", poolId, scId, assetId))));\n }\n\n D18 pricePoolPerAsset = poolManager.pricePoolPerAsset(poolId, scId, assetId, true);\n return pricePoolPerAsset;\n }\n\n function _pricePoolPerShare(PoolId poolId, ShareClassId scId) internal view returns (D18) {\n if (TransientStorageLib.tloadBool(keccak256(abi.encode(\"pricePoolPerShareIsSet\", poolId, scId)))) {\n return d18(TransientStorageLib.tloadUint128(keccak256(abi.encode(\"pricePoolPerShare\", poolId, scId))));\n }\n\n D18 pricePoolPerShare = poolManager.pricePoolPerShare(poolId, scId, true);\n return pricePoolPerShare;\n }\n}\n" + }, + "src/vaults/BaseRequestManager.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {D18} from \"src/misc/types/D18.sol\";\nimport {Recoverable} from \"src/misc/Recoverable.sol\";\nimport {IAuth} from \"src/misc/interfaces/IAuth.sol\";\n\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {PricingLib} from \"src/common/libraries/PricingLib.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nimport {IPoolManager, VaultDetails} from \"src/vaults/interfaces/IPoolManager.sol\";\nimport {IBaseRequestManager} from \"src/vaults/interfaces/investments/IBaseRequestManager.sol\";\nimport {IPoolEscrowProvider} from \"src/vaults/interfaces/factories/IPoolEscrowFactory.sol\";\nimport {IBaseVault, VaultKind} from \"src/vaults/interfaces/IBaseVaults.sol\";\nimport {IPoolEscrow, IEscrow} from \"src/vaults/interfaces/IEscrow.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\n\nabstract contract BaseRequestManager is Auth, Recoverable, IBaseRequestManager {\n using MathLib for uint256;\n\n address public immutable root;\n IEscrow public immutable globalEscrow;\n\n IPoolManager public poolManager;\n IPoolEscrowProvider public poolEscrowProvider;\n\n mapping(PoolId poolId => mapping(ShareClassId scId => mapping(AssetId assetId => IBaseVault vault))) public vault;\n\n constructor(IEscrow globalEscrow_, address root_, address deployer) Auth(deployer) {\n globalEscrow = globalEscrow_;\n root = root_;\n }\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IBaseRequestManager\n function file(bytes32 what, address data) external virtual auth {\n if (what == \"poolManager\") poolManager = IPoolManager(data);\n else if (what == \"poolEscrowProvider\") poolEscrowProvider = IPoolEscrowProvider(data);\n else revert FileUnrecognizedParam();\n emit File(what, data);\n }\n\n /// @inheritdoc IBaseRequestManager\n function addVault(PoolId poolId, ShareClassId scId, IBaseVault vault_, address asset_, AssetId assetId)\n public\n virtual\n auth\n {\n address token = vault_.share();\n\n require(vault_.asset() == asset_, AssetMismatch());\n require(address(vault[poolId][scId][assetId]) == address(0), VaultAlreadyExists());\n\n vault[poolId][scId][assetId] = IBaseVault(address(vault_));\n IAuth(token).rely(address(vault_));\n IShareToken(token).updateVault(vault_.asset(), address(vault_));\n rely(address(vault_));\n }\n\n /// @inheritdoc IBaseRequestManager\n function removeVault(PoolId poolId, ShareClassId scId, IBaseVault vault_, address asset_, AssetId assetId)\n public\n virtual\n auth\n {\n address token = vault_.share();\n\n require(vault_.asset() == asset_, AssetMismatch());\n require(address(vault[poolId][scId][assetId]) != address(0), VaultDoesNotExist());\n\n delete vault[poolId][scId][assetId];\n\n IAuth(token).deny(address(vault_));\n IShareToken(token).updateVault(vault_.asset(), address(0));\n deny(address(vault_));\n }\n\n //----------------------------------------------------------------------------------------------\n // View methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IBaseRequestManager\n function convertToShares(IBaseVault vault_, uint256 assets) public view virtual returns (uint256 shares) {\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n (D18 pricePoolPerAsset, D18 pricePoolPerShare) =\n poolManager.pricesPoolPer(vault_.poolId(), vault_.scId(), vaultDetails.assetId, false);\n\n return _assetToShareAmount(\n vault_, vaultDetails, assets, pricePoolPerAsset, pricePoolPerShare, MathLib.Rounding.Down\n );\n }\n\n /// @inheritdoc IBaseRequestManager\n function convertToAssets(IBaseVault vault_, uint256 shares) public view virtual returns (uint256 assets) {\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n (D18 pricePoolPerAsset, D18 pricePoolPerShare) =\n poolManager.pricesPoolPer(vault_.poolId(), vault_.scId(), vaultDetails.assetId, false);\n\n return _shareToAssetAmount(\n vault_, vaultDetails, shares, pricePoolPerAsset, pricePoolPerShare, MathLib.Rounding.Down\n );\n }\n\n /// @inheritdoc IBaseRequestManager\n function priceLastUpdated(IBaseVault vault_) public view virtual returns (uint64 lastUpdated) {\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n\n (uint64 shareLastUpdated,,) = poolManager.markersPricePoolPerShare(vault_.poolId(), vault_.scId());\n (uint64 assetLastUpdated,,) =\n poolManager.markersPricePoolPerAsset(vault_.poolId(), vault_.scId(), vaultDetails.assetId);\n\n // Choose the latest update to be the marker\n lastUpdated = MathLib.max(shareLastUpdated, assetLastUpdated).toUint64();\n }\n\n /// @inheritdoc IBaseRequestManager\n function poolEscrow(PoolId poolId) public view returns (IPoolEscrow) {\n return poolEscrowProvider.escrow(poolId);\n }\n\n /// @inheritdoc IBaseRequestManager\n function vaultByAssetId(PoolId poolId, ShareClassId scId, AssetId assetId) public view returns (IBaseVault) {\n return vault[poolId][scId][assetId];\n }\n\n function _assetToShareAmount(\n IBaseVault vault_,\n VaultDetails memory vaultDetails,\n uint256 assets,\n D18 pricePoolPerAsset,\n D18 pricePoolPerShare,\n MathLib.Rounding rounding\n ) internal view returns (uint256 shares) {\n return PricingLib.assetToShareAmount(\n vault_.share(),\n vaultDetails.asset,\n vaultDetails.tokenId,\n assets.toUint128(),\n pricePoolPerAsset,\n pricePoolPerShare,\n rounding\n );\n }\n\n function _shareToAssetAmount(\n IBaseVault vault_,\n VaultDetails memory vaultDetails,\n uint256 shares,\n D18 pricePoolPerAsset,\n D18 pricePoolPerShare,\n MathLib.Rounding rounding\n ) internal view returns (uint256 assets) {\n return PricingLib.shareToAssetAmount(\n vault_.share(),\n shares.toUint128(),\n vaultDetails.asset,\n vaultDetails.tokenId,\n pricePoolPerAsset,\n pricePoolPerShare,\n rounding\n );\n }\n}\n" + }, + "src/vaults/BaseVaults.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport \"src/misc/interfaces/IERC7540.sol\";\nimport \"src/misc/interfaces/IERC7575.sol\";\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {IERC20Metadata} from \"src/misc/interfaces/IERC20.sol\";\nimport {EIP712Lib} from \"src/misc/libraries/EIP712Lib.sol\";\nimport {SignatureLib} from \"src/misc/libraries/SignatureLib.sol\";\nimport {SafeTransferLib} from \"src/misc/libraries/SafeTransferLib.sol\";\nimport {Recoverable} from \"src/misc/Recoverable.sol\";\n\nimport {IRoot} from \"src/common/interfaces/IRoot.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nimport {IBaseVault, IAsyncRedeemVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\nimport {IERC7575} from \"src/misc/interfaces/IERC7575.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\nimport {IAsyncRedeemManager} from \"src/vaults/interfaces/investments/IAsyncRedeemManager.sol\";\nimport {ISyncDepositManager} from \"src/vaults/interfaces/investments/ISyncDepositManager.sol\";\nimport {IBaseRequestManager} from \"src/vaults/interfaces/investments/IBaseRequestManager.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\n\nabstract contract BaseVault is Auth, Recoverable, IBaseVault {\n /// @dev Requests for Centrifuge pool are non-fungible and all have ID = 0\n uint256 internal constant REQUEST_ID = 0;\n\n IRoot public immutable root;\n /// @dev this naming MUST NEVER change - due to legacy v2 vaults\n IBaseRequestManager public manager;\n\n /// @inheritdoc IBaseVault\n PoolId public immutable poolId;\n /// @inheritdoc IBaseVault\n ShareClassId public immutable scId;\n\n /// @inheritdoc IERC7575\n address public immutable asset;\n\n /// @inheritdoc IERC7575\n address public immutable share;\n uint8 internal immutable _shareDecimals;\n\n /// --- ERC7741 ---\n bytes32 private immutable nameHash;\n bytes32 private immutable versionHash;\n uint256 public immutable deploymentChainId;\n bytes32 private immutable _DOMAIN_SEPARATOR;\n bytes32 public constant AUTHORIZE_OPERATOR_TYPEHASH =\n keccak256(\"AuthorizeOperator(address controller,address operator,bool approved,bytes32 nonce,uint256 deadline)\");\n\n /// @inheritdoc IERC7741\n mapping(address controller => mapping(bytes32 nonce => bool used)) public authorizations;\n\n /// @inheritdoc IERC7540Operator\n mapping(address => mapping(address => bool)) public isOperator;\n\n constructor(\n PoolId poolId_,\n ShareClassId scId_,\n address asset_,\n IShareToken token_,\n address root_,\n IBaseRequestManager manager_\n ) Auth(msg.sender) {\n poolId = poolId_;\n scId = scId_;\n asset = asset_;\n share = address(token_);\n _shareDecimals = IERC20Metadata(share).decimals();\n root = IRoot(root_);\n manager = IBaseRequestManager(manager_);\n\n nameHash = keccak256(bytes(\"Centrifuge\"));\n versionHash = keccak256(bytes(\"1\"));\n deploymentChainId = block.chainid;\n _DOMAIN_SEPARATOR = EIP712Lib.calculateDomainSeparator(nameHash, versionHash);\n }\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n function file(bytes32 what, address data) external virtual auth {\n if (what == \"manager\") manager = IBaseRequestManager(data);\n else revert FileUnrecognizedParam();\n emit File(what, data);\n }\n\n /// @inheritdoc IERC7540Operator\n function setOperator(address operator, bool approved) public virtual returns (bool success) {\n require(msg.sender != operator, CannotSetSelfAsOperator());\n isOperator[msg.sender][operator] = approved;\n emit OperatorSet(msg.sender, operator, approved);\n success = true;\n }\n\n /// @inheritdoc IBaseVault\n function setEndorsedOperator(address owner, bool approved) public virtual {\n require(msg.sender != owner, CannotSetSelfAsOperator());\n require(root.endorsed(msg.sender), NotEndorsed());\n isOperator[owner][msg.sender] = approved;\n emit OperatorSet(owner, msg.sender, approved);\n }\n\n /// @inheritdoc IERC7741\n function DOMAIN_SEPARATOR() public view returns (bytes32) {\n return block.chainid == deploymentChainId\n ? _DOMAIN_SEPARATOR\n : EIP712Lib.calculateDomainSeparator(nameHash, versionHash);\n }\n\n /// @inheritdoc IERC7741\n function authorizeOperator(\n address controller,\n address operator,\n bool approved,\n bytes32 nonce,\n uint256 deadline,\n bytes memory signature\n ) external returns (bool success) {\n require(controller != operator, CannotSetSelfAsOperator());\n require(block.timestamp <= deadline, ExpiredAuthorization());\n require(!authorizations[controller][nonce], AlreadyUsedAuthorization());\n\n authorizations[controller][nonce] = true;\n\n bytes32 digest = keccak256(\n abi.encodePacked(\n \"\\x19\\x01\",\n DOMAIN_SEPARATOR(),\n keccak256(abi.encode(AUTHORIZE_OPERATOR_TYPEHASH, controller, operator, approved, nonce, deadline))\n )\n );\n\n require(SignatureLib.isValidSignature(controller, digest, signature), InvalidAuthorization());\n\n isOperator[controller][operator] = approved;\n emit OperatorSet(controller, operator, approved);\n\n success = true;\n }\n\n /// @inheritdoc IERC7741\n function invalidateNonce(bytes32 nonce) external {\n authorizations[msg.sender][nonce] = true;\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-165\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC165\n function supportsInterface(bytes4 interfaceId) public pure virtual override returns (bool) {\n return interfaceId == type(IERC7540Operator).interfaceId || interfaceId == type(IERC7741).interfaceId\n || interfaceId == type(IERC7714).interfaceId || interfaceId == type(IERC7575).interfaceId\n || interfaceId == type(IERC165).interfaceId;\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-4626\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC7575\n function totalAssets() external view returns (uint256) {\n return convertToAssets(IERC20Metadata(share).totalSupply());\n }\n\n /// @inheritdoc IERC7575\n /// @notice The calculation is based on the token price from the most recent epoch retrieved from Centrifuge.\n /// The actual conversion MAY change between order submission and execution.\n function convertToShares(uint256 assets) public view returns (uint256 shares) {\n shares = manager.convertToShares(this, assets);\n }\n\n /// @inheritdoc IERC7575\n /// @notice The calculation is based on the token price from the most recent epoch retrieved from Centrifuge.\n /// The actual conversion MAY change between order submission and execution.\n function convertToAssets(uint256 shares) public view returns (uint256 assets) {\n assets = manager.convertToAssets(this, shares);\n }\n\n //----------------------------------------------------------------------------------------------\n // Helpers\n //----------------------------------------------------------------------------------------------\n\n /// @notice Price of 1 unit of share, quoted in the decimals of the asset.\n function pricePerShare() external view returns (uint256) {\n return convertToAssets(10 ** _shareDecimals);\n }\n\n /// @notice Returns timestamp of the last share price update.\n function priceLastUpdated() external view returns (uint64) {\n return manager.priceLastUpdated(this);\n }\n\n /// @inheritdoc IERC7714\n function isPermissioned(address controller) external view returns (bool) {\n return IShareToken(share).checkTransferRestriction(address(0), controller, 0);\n }\n\n /// @notice Ensures msg.sender can operate on behalf of controller.\n function _validateController(address controller) internal view {\n require(controller == msg.sender || isOperator[controller][msg.sender], InvalidController());\n }\n}\n\nabstract contract BaseAsyncRedeemVault is BaseVault, IAsyncRedeemVault {\n IAsyncRedeemManager public asyncRedeemManager;\n\n constructor(IAsyncRedeemManager asyncRequestManager_) {\n asyncRedeemManager = asyncRequestManager_;\n }\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n function file(bytes32 what, address data) external virtual override auth {\n if (what == \"manager\") manager = IBaseRequestManager(data);\n else if (what == \"asyncRedeemManager\") asyncRedeemManager = IAsyncRedeemManager(data);\n else revert FileUnrecognizedParam();\n emit File(what, data);\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-7540 redeem\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC7540Redeem\n function requestRedeem(uint256 shares, address controller, address owner) public returns (uint256) {\n require(IShareToken(share).balanceOf(owner) >= shares, InsufficientBalance());\n\n // If msg.sender is operator of owner, the transfer is executed as if\n // the sender is the owner, to bypass the allowance check\n address sender = isOperator[owner][msg.sender] ? owner : msg.sender;\n\n require(asyncRedeemManager.requestRedeem(this, shares, controller, owner, sender), RequestRedeemFailed());\n IShareToken(share).authTransferFrom(sender, owner, address(manager.globalEscrow()), shares);\n\n emit RedeemRequest(controller, owner, REQUEST_ID, msg.sender, shares);\n return REQUEST_ID;\n }\n\n /// @inheritdoc IERC7540Redeem\n function pendingRedeemRequest(uint256, address controller) public view returns (uint256 pendingShares) {\n pendingShares = asyncRedeemManager.pendingRedeemRequest(this, controller);\n }\n\n /// @inheritdoc IERC7540Redeem\n function claimableRedeemRequest(uint256, address controller) external view returns (uint256 claimableShares) {\n claimableShares = maxRedeem(controller);\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-7887\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC7887Redeem\n function cancelRedeemRequest(uint256, address controller) external {\n _validateController(controller);\n asyncRedeemManager.cancelRedeemRequest(this, controller, msg.sender);\n emit CancelRedeemRequest(controller, REQUEST_ID, msg.sender);\n }\n\n /// @inheritdoc IERC7887Redeem\n function pendingCancelRedeemRequest(uint256, address controller) public view returns (bool isPending) {\n isPending = asyncRedeemManager.pendingCancelRedeemRequest(this, controller);\n }\n\n /// @inheritdoc IERC7887Redeem\n function claimableCancelRedeemRequest(uint256, address controller) public view returns (uint256 claimableShares) {\n claimableShares = asyncRedeemManager.claimableCancelRedeemRequest(this, controller);\n }\n\n /// @inheritdoc IERC7887Redeem\n function claimCancelRedeemRequest(uint256, address receiver, address controller)\n external\n returns (uint256 shares)\n {\n _validateController(controller);\n shares = asyncRedeemManager.claimCancelRedeemRequest(this, receiver, controller);\n emit CancelRedeemClaim(receiver, controller, REQUEST_ID, msg.sender, shares);\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-7540 claim\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC7575\n /// @notice DOES NOT support controller != msg.sender since shares are already transferred on requestRedeem\n function withdraw(uint256 assets, address receiver, address controller) public returns (uint256 shares) {\n _validateController(controller);\n shares = asyncRedeemManager.withdraw(this, assets, receiver, controller);\n emit Withdraw(msg.sender, receiver, controller, assets, shares);\n }\n\n /// @inheritdoc IERC7575\n /// @notice DOES NOT support controller != msg.sender since shares are already transferred on requestRedeem.\n /// When claiming redemption requests using redeem(), there can be some precision loss leading to dust.\n /// It is recommended to use withdraw() to claim redemption requests instead.\n function redeem(uint256 shares, address receiver, address controller) external returns (uint256 assets) {\n _validateController(controller);\n assets = asyncRedeemManager.redeem(this, shares, receiver, controller);\n emit Withdraw(msg.sender, receiver, controller, assets, shares);\n }\n\n //----------------------------------------------------------------------------------------------\n // Event emitters\n //----------------------------------------------------------------------------------------------\n\n function onRedeemRequest(address controller, address owner, uint256 shares) public virtual auth {\n emit RedeemRequest(controller, owner, REQUEST_ID, msg.sender, shares);\n }\n\n function onRedeemClaimable(address controller, uint256 assets, uint256 shares) public virtual auth {\n emit RedeemClaimable(controller, REQUEST_ID, assets, shares);\n }\n\n function onCancelRedeemClaimable(address controller, uint256 shares) public virtual auth {\n emit CancelRedeemClaimable(controller, REQUEST_ID, shares);\n }\n\n //----------------------------------------------------------------------------------------------\n // View methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC165\n function supportsInterface(bytes4 interfaceId) public pure virtual override(BaseVault, IERC165) returns (bool) {\n return super.supportsInterface(interfaceId) || interfaceId == type(IERC7540Redeem).interfaceId\n || interfaceId == type(IERC7887Redeem).interfaceId;\n }\n\n /// @inheritdoc IERC7575\n function maxWithdraw(address controller) public view returns (uint256 maxAssets) {\n maxAssets = asyncRedeemManager.maxWithdraw(this, controller);\n }\n\n /// @inheritdoc IERC7575\n function maxRedeem(address controller) public view returns (uint256 maxShares) {\n maxShares = asyncRedeemManager.maxRedeem(this, controller);\n }\n\n /// @dev Preview functions for ERC-7540 vaults revert\n function previewWithdraw(uint256) external pure returns (uint256) {\n revert();\n }\n\n /// @dev Preview functions for ERC-7540 vaults revert\n function previewRedeem(uint256) external pure returns (uint256) {\n revert();\n }\n}\n\nabstract contract BaseSyncDepositVault is BaseVault {\n ISyncDepositManager public syncDepositManager;\n\n constructor(ISyncDepositManager syncRequestManager_) {\n syncDepositManager = syncRequestManager_;\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-4626\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC7575\n function maxDeposit(address owner) public view returns (uint256 maxAssets) {\n maxAssets = syncDepositManager.maxDeposit(this, owner);\n }\n\n /// @inheritdoc IERC7575\n function previewDeposit(uint256 assets) external view override returns (uint256 shares) {\n shares = syncDepositManager.previewDeposit(this, msg.sender, assets);\n }\n\n /// @inheritdoc IERC7575\n function deposit(uint256 assets, address receiver) external returns (uint256 shares) {\n shares = syncDepositManager.deposit(this, assets, receiver, msg.sender);\n // NOTE: For security reasons, transfer must stay at end of call despite the fact that it logically should\n // happen before depositing in the manager\n SafeTransferLib.safeTransferFrom(asset, msg.sender, address(manager.poolEscrow(poolId)), assets);\n emit Deposit(receiver, msg.sender, assets, shares);\n }\n\n /// @inheritdoc IERC7575\n function maxMint(address owner) public view returns (uint256 maxShares) {\n maxShares = syncDepositManager.maxMint(this, owner);\n }\n\n /// @inheritdoc IERC7575\n function previewMint(uint256 shares) external view returns (uint256 assets) {\n assets = syncDepositManager.previewMint(this, msg.sender, shares);\n }\n\n /// @inheritdoc IERC7575\n function mint(uint256 shares, address receiver) public returns (uint256 assets) {\n assets = syncDepositManager.mint(this, shares, receiver, msg.sender);\n // NOTE: For security reasons, transfer must stay at end of call\n SafeTransferLib.safeTransferFrom(asset, msg.sender, address(manager.poolEscrow(poolId)), assets);\n emit Deposit(receiver, msg.sender, assets, shares);\n }\n\n /// @inheritdoc IERC165\n function supportsInterface(bytes4 interfaceId) public pure virtual override(BaseVault) returns (bool) {\n return super.supportsInterface(interfaceId);\n }\n}\n" + }, + "src/vaults/Escrow.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {IERC20} from \"src/misc/interfaces/IERC20.sol\";\nimport {IERC6909} from \"src/misc/interfaces/IERC6909.sol\";\nimport {SafeTransferLib} from \"src/misc/libraries/SafeTransferLib.sol\";\nimport {Recoverable} from \"src/misc/Recoverable.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {Holding, IPoolEscrow, IEscrow} from \"src/vaults/interfaces/IEscrow.sol\";\n\ncontract Escrow is Auth, IEscrow {\n constructor(address deployer) Auth(deployer) {}\n\n /// @inheritdoc IEscrow\n function authTransferTo(address asset, uint256 tokenId, address receiver, uint256 amount) public auth {\n if (tokenId == 0) {\n uint256 balance = IERC20(asset).balanceOf(address(this));\n require(balance >= amount, InsufficientBalance(asset, tokenId, amount, balance));\n\n SafeTransferLib.safeTransfer(asset, receiver, amount);\n } else {\n uint256 balance = IERC6909(asset).balanceOf(address(this), tokenId);\n require(balance >= amount, InsufficientBalance(asset, tokenId, amount, balance));\n\n IERC6909(asset).transfer(receiver, tokenId, amount);\n }\n\n emit AuthTransferTo(asset, tokenId, receiver, amount);\n }\n\n /// @inheritdoc IEscrow\n function authTransferTo(address asset, address receiver, uint256 amount) external auth {\n authTransferTo(asset, 0, receiver, amount);\n }\n}\n\n/// @title Escrow\n/// @notice Escrow contract that holds assets for a specific pool separated by share classes.\n/// Only wards can approve funds to be taken out.\ncontract PoolEscrow is Escrow, Recoverable, IPoolEscrow {\n /// @dev The underlying pool id\n PoolId public immutable poolId;\n\n mapping(ShareClassId scId => mapping(address asset => mapping(uint256 tokenId => Holding))) public holding;\n\n constructor(PoolId poolId_, address deployer) Escrow(deployer) {\n poolId = poolId_;\n }\n\n receive() external payable {}\n\n /// @inheritdoc IPoolEscrow\n function deposit(ShareClassId scId, address asset, uint256 tokenId, uint128 value) external auth {\n holding[scId][asset][tokenId].total += value;\n\n emit Deposit(asset, tokenId, poolId, scId, value);\n }\n\n /// @inheritdoc IPoolEscrow\n function withdraw(ShareClassId scId, address asset, uint256 tokenId, uint128 value) external auth {\n Holding storage holding_ = holding[scId][asset][tokenId];\n uint128 balance = holding_.total - holding_.reserved;\n require(balance >= value, InsufficientBalance(asset, tokenId, value, balance));\n\n holding_.total -= value;\n\n emit Withdraw(asset, tokenId, poolId, scId, value);\n }\n\n /// @inheritdoc IPoolEscrow\n function reserveIncrease(ShareClassId scId, address asset, uint256 tokenId, uint128 value) external auth {\n uint128 newValue = holding[scId][asset][tokenId].reserved + value;\n holding[scId][asset][tokenId].reserved = newValue;\n\n emit IncreaseReserve(asset, tokenId, poolId, scId, value, newValue);\n }\n\n /// @inheritdoc IPoolEscrow\n function reserveDecrease(ShareClassId scId, address asset, uint256 tokenId, uint128 value) external auth {\n uint128 prevValue = holding[scId][asset][tokenId].reserved;\n uint128 value_ = value;\n require(prevValue >= value_, InsufficientReservedAmount());\n\n uint128 newValue = prevValue - value_;\n holding[scId][asset][tokenId].reserved = newValue;\n\n emit DecreaseReserve(asset, tokenId, poolId, scId, value, newValue);\n }\n\n /// @inheritdoc IPoolEscrow\n function availableBalanceOf(ShareClassId scId, address asset, uint256 tokenId) public view returns (uint128) {\n Holding storage holding_ = holding[scId][asset][tokenId];\n if (holding_.total < holding_.reserved) return 0;\n return holding_.total - holding_.reserved;\n }\n}\n" + }, + "src/vaults/PoolManager.sol": { + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.28;\n\nimport {IERC20Metadata, IERC20Wrapper} from \"src/misc/interfaces/IERC20.sol\";\nimport {IERC6909MetadataExt} from \"src/misc/interfaces/IERC6909.sol\";\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {IAuth} from \"src/misc/interfaces/IAuth.sol\";\nimport {D18} from \"src/misc/types/D18.sol\";\nimport {Recoverable} from \"src/misc/Recoverable.sol\";\nimport {IERC165} from \"src/misc/interfaces/IERC7575.sol\";\nimport {ReentrancyProtection} from \"src/misc/ReentrancyProtection.sol\";\n\nimport {VaultUpdateKind, MessageLib, UpdateContractType} from \"src/common/libraries/MessageLib.sol\";\nimport {IGateway} from \"src/common/interfaces/IGateway.sol\";\nimport {IPoolManagerGatewayHandler} from \"src/common/interfaces/IGatewayHandlers.sol\";\nimport {IVaultMessageSender} from \"src/common/interfaces/IGatewaySenders.sol\";\nimport {newAssetId, AssetId} from \"src/common/types/AssetId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {PricingLib} from \"src/common/libraries/PricingLib.sol\";\n\nimport {IVaultFactory} from \"src/vaults/interfaces/factories/IVaultFactory.sol\";\nimport {IBaseVault, VaultKind} from \"src/vaults/interfaces/IBaseVaults.sol\";\nimport {IBaseRequestManager} from \"src/vaults/interfaces/investments/IBaseRequestManager.sol\";\nimport {ITokenFactory} from \"src/vaults/interfaces/factories/ITokenFactory.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\nimport {IPoolEscrowFactory} from \"src/vaults/interfaces/factories/IPoolEscrowFactory.sol\";\nimport {IHook} from \"src/common/interfaces/IHook.sol\";\nimport {IUpdateContract} from \"src/vaults/interfaces/IUpdateContract.sol\";\nimport {\n AssetIdKey,\n Pool,\n ShareClassDetails,\n Price,\n VaultDetails,\n IPoolManager\n} from \"src/vaults/interfaces/IPoolManager.sol\";\nimport {IAsyncRequestManager} from \"src/vaults/interfaces/investments/IAsyncRequestManager.sol\";\nimport {ISyncRequestManager} from \"src/vaults/interfaces/investments/ISyncRequestManager.sol\";\nimport {IPoolEscrow} from \"src/vaults/interfaces/IEscrow.sol\";\n\n/// @title Pool Manager\n/// @notice This contract manages which pools & share classes exist,\n/// as well as managing allowed pool currencies, and incoming and outgoing transfers.\ncontract PoolManager is\n Auth,\n Recoverable,\n ReentrancyProtection,\n IPoolManager,\n IUpdateContract,\n IPoolManagerGatewayHandler\n{\n using CastLib for *;\n using MessageLib for *;\n using BytesLib for bytes;\n using MathLib for uint256;\n\n uint8 internal constant MIN_DECIMALS = 2;\n uint8 internal constant MAX_DECIMALS = 18;\n\n IGateway public gateway;\n address public balanceSheet;\n ITokenFactory public tokenFactory;\n IVaultMessageSender public sender;\n IPoolEscrowFactory public poolEscrowFactory;\n IAsyncRequestManager public asyncRequestManager;\n ISyncRequestManager public syncRequestManager;\n\n uint64 internal _assetCounter;\n\n mapping(PoolId poolId => Pool) public pools;\n mapping(IVaultFactory factory => bool) public vaultFactory;\n\n mapping(IBaseVault => VaultDetails) internal _vaultDetails;\n mapping(AssetId assetId => AssetIdKey) internal _idToAsset;\n mapping(address asset => mapping(uint256 tokenId => AssetId assetId)) internal _assetToId;\n\n constructor(ITokenFactory tokenFactory_, address deployer) Auth(deployer) {\n tokenFactory = tokenFactory_;\n }\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IPoolManager\n function file(bytes32 what, address data) external auth {\n if (what == \"sender\") sender = IVaultMessageSender(data);\n else if (what == \"tokenFactory\") tokenFactory = ITokenFactory(data);\n else if (what == \"gateway\") gateway = IGateway(data);\n else if (what == \"balanceSheet\") balanceSheet = data;\n else if (what == \"poolEscrowFactory\") poolEscrowFactory = IPoolEscrowFactory(data);\n else if (what == \"asyncRequestManager\") asyncRequestManager = IAsyncRequestManager(data);\n else if (what == \"syncRequestManager\") syncRequestManager = ISyncRequestManager(data);\n else revert FileUnrecognizedParam();\n emit File(what, data);\n }\n\n /// @inheritdoc IPoolManager\n function file(bytes32 what, address factory, bool status) external auth {\n if (what == \"vaultFactory\") {\n vaultFactory[IVaultFactory(factory)] = status;\n } else {\n revert FileUnrecognizedParam();\n }\n emit File(what, factory, status);\n }\n\n //----------------------------------------------------------------------------------------------\n // Outgoing methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IPoolManager\n function transferShares(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bytes32 receiver, uint128 amount)\n external\n payable\n protected\n {\n IShareToken share = IShareToken(shareToken(poolId, scId));\n require(centrifugeId != sender.localCentrifugeId(), LocalTransferNotAllowed());\n require(\n share.checkTransferRestriction(msg.sender, address(uint160(centrifugeId)), amount),\n CrossChainTransferNotAllowed()\n );\n\n gateway.payTransaction{value: msg.value}(msg.sender);\n\n share.authTransferFrom(msg.sender, msg.sender, address(this), amount);\n share.burn(address(this), amount);\n\n emit TransferShares(centrifugeId, poolId, scId, msg.sender, receiver, amount);\n sender.sendTransferShares(centrifugeId, poolId, scId, receiver, amount);\n }\n\n // @inheritdoc IPoolManager\n function registerAsset(uint16 centrifugeId, address asset, uint256 tokenId)\n external\n payable\n protected\n returns (AssetId assetId)\n {\n string memory name;\n string memory symbol;\n uint8 decimals;\n\n decimals = _safeGetAssetDecimals(asset, tokenId);\n require(decimals >= MIN_DECIMALS, TooFewDecimals());\n require(decimals <= MAX_DECIMALS, TooManyDecimals());\n\n gateway.payTransaction{value: msg.value}(msg.sender);\n\n if (tokenId == 0) {\n IERC20Metadata meta = IERC20Metadata(asset);\n name = meta.name();\n symbol = meta.symbol();\n } else {\n IERC6909MetadataExt meta = IERC6909MetadataExt(asset);\n name = meta.name(tokenId);\n symbol = meta.symbol(tokenId);\n }\n\n assetId = _assetToId[asset][tokenId];\n if (assetId.raw() == 0) {\n _assetCounter++;\n assetId = newAssetId(sender.localCentrifugeId(), _assetCounter);\n\n _idToAsset[assetId] = AssetIdKey(asset, tokenId);\n _assetToId[asset][tokenId] = assetId;\n\n emit RegisterAsset(assetId, asset, tokenId, name, symbol, decimals);\n }\n\n sender.sendRegisterAsset(centrifugeId, assetId, decimals);\n }\n\n //----------------------------------------------------------------------------------------------\n // Incoming\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IPoolManagerGatewayHandler\n function addPool(PoolId poolId) public auth {\n Pool storage pool = pools[poolId];\n require(pool.createdAt == 0, PoolAlreadyAdded());\n pool.createdAt = block.timestamp;\n\n IPoolEscrow escrow = poolEscrowFactory.newEscrow(poolId);\n gateway.setRefundAddress(PoolId.wrap(poolId.raw()), escrow);\n\n emit AddPool(poolId);\n }\n\n /// @inheritdoc IPoolManagerGatewayHandler\n function addShareClass(\n PoolId poolId,\n ShareClassId scId,\n string memory name,\n string memory symbol,\n uint8 decimals,\n bytes32 salt,\n address hook\n ) public auth {\n require(decimals >= MIN_DECIMALS, TooFewDecimals());\n require(decimals <= MAX_DECIMALS, TooManyDecimals());\n require(isPoolActive(poolId), InvalidPool());\n\n Pool storage pool = pools[poolId];\n require(address(pool.shareClasses[scId].shareToken) == address(0), ShareClassAlreadyRegistered());\n\n // Hook can be address zero if the share token is fully permissionless and has no custom logic\n require(hook == address(0) || _isValidHook(hook), InvalidHook());\n\n address[] memory tokenWards = new address[](2);\n tokenWards[0] = address(this);\n // BalanceSheet needs this in order to mint shares\n tokenWards[1] = balanceSheet;\n\n IShareToken shareToken_ = tokenFactory.newToken(name, symbol, decimals, salt, tokenWards);\n\n if (hook != address(0)) {\n shareToken_.file(\"hook\", hook);\n }\n\n pool.shareClasses[scId].shareToken = shareToken_;\n\n emit AddShareClass(poolId, scId, shareToken_);\n }\n\n /// @inheritdoc IPoolManagerGatewayHandler\n function updateShareMetadata(PoolId poolId, ShareClassId scId, string memory name, string memory symbol)\n public\n auth\n {\n IShareToken shareToken_ = shareToken(poolId, scId);\n\n require(\n keccak256(bytes(shareToken_.name())) != keccak256(bytes(name))\n || keccak256(bytes(shareToken_.symbol())) != keccak256(bytes(symbol)),\n OldMetadata()\n );\n\n shareToken_.file(\"name\", name);\n shareToken_.file(\"symbol\", symbol);\n }\n\n /// @inheritdoc IPoolManagerGatewayHandler\n function updatePricePoolPerShare(PoolId poolId, ShareClassId scId, uint128 price, uint64 computedAt) public auth {\n ShareClassDetails storage shareClass = _shareClass(poolId, scId);\n\n require(computedAt >= shareClass.pricePoolPerShare.computedAt, CannotSetOlderPrice());\n\n shareClass.pricePoolPerShare = Price(price, computedAt, shareClass.pricePoolPerShare.maxAge);\n emit PriceUpdate(poolId, scId, price, computedAt);\n }\n\n /// @inheritdoc IPoolManagerGatewayHandler\n function updatePricePoolPerAsset(\n PoolId poolId,\n ShareClassId scId,\n AssetId assetId,\n uint128 poolPerAsset_,\n uint64 computedAt\n ) public auth {\n ShareClassDetails storage shareClass = _shareClass(poolId, scId);\n\n (address asset, uint256 tokenId) = idToAsset(assetId);\n Price storage poolPerAsset = shareClass.pricePoolPerAsset[asset][tokenId];\n require(computedAt >= poolPerAsset.computedAt, CannotSetOlderPrice());\n\n // Disable expiration of the price\n if (poolPerAsset.computedAt == 0) {\n poolPerAsset.maxAge = type(uint64).max;\n }\n poolPerAsset.price = poolPerAsset_;\n poolPerAsset.computedAt = computedAt;\n\n emit PriceUpdate(poolId, scId, asset, tokenId, poolPerAsset_, computedAt);\n }\n\n /// @inheritdoc IPoolManagerGatewayHandler\n function updateRestriction(PoolId poolId, ShareClassId scId, bytes memory update_) public auth {\n IShareToken shareToken_ = shareToken(poolId, scId);\n address hook = shareToken_.hook();\n require(hook != address(0), InvalidHook());\n IHook(hook).updateRestriction(address(shareToken_), update_);\n }\n\n /// @inheritdoc IPoolManagerGatewayHandler\n function updateContract(PoolId poolId, ShareClassId scId, address target, bytes memory update_) public auth {\n if (target == address(this)) {\n update(poolId, scId, update_);\n } else {\n IUpdateContract(target).update(poolId, scId, update_);\n }\n\n emit UpdateContract(poolId, scId, target, update_);\n }\n\n /// @inheritdoc IPoolManagerGatewayHandler\n function updateShareHook(PoolId poolId, ShareClassId scId, address hook) public auth {\n IShareToken shareToken_ = shareToken(poolId, scId);\n require(hook != shareToken_.hook(), OldHook());\n shareToken_.file(\"hook\", hook);\n }\n\n /// @inheritdoc IPoolManagerGatewayHandler\n function handleTransferShares(PoolId poolId, ShareClassId scId, address destinationAddress, uint128 amount)\n public\n auth\n {\n IShareToken shareToken_ = shareToken(poolId, scId);\n\n shareToken_.mint(destinationAddress, amount);\n }\n\n /// @inheritdoc IUpdateContract\n /// @notice The pool manager either deploys the vault if a factory address is provided\n /// or it simply links/unlinks the vault.\n function update(PoolId poolId, ShareClassId scId, bytes memory payload) public auth {\n uint8 kind = uint8(MessageLib.updateContractType(payload));\n\n if (kind == uint8(UpdateContractType.VaultUpdate)) {\n MessageLib.UpdateContractVaultUpdate memory m = MessageLib.deserializeUpdateContractVaultUpdate(payload);\n\n if (m.kind == uint8(VaultUpdateKind.DeployAndLink)) {\n IVaultFactory factory = IVaultFactory(m.vaultOrFactory.toAddress());\n\n IBaseVault vault = deployVault(poolId, scId, AssetId.wrap(m.assetId), factory);\n linkVault(poolId, scId, AssetId.wrap(m.assetId), vault);\n } else {\n IBaseVault vault = IBaseVault(m.vaultOrFactory.toAddress());\n\n // Needed as safeguard against non-validated vaults\n // I.e. we only accept vaults that have been deployed by the pool manager\n require(_vaultDetails[vault].asset != address(0), UnknownVault());\n\n if (m.kind == uint8(VaultUpdateKind.Link)) {\n linkVault(poolId, scId, AssetId.wrap(m.assetId), vault);\n } else if (m.kind == uint8(VaultUpdateKind.Unlink)) {\n unlinkVault(poolId, scId, AssetId.wrap(m.assetId), vault);\n } else {\n revert MalformedVaultUpdateMessage();\n }\n }\n } else if (kind == uint8(UpdateContractType.MaxAssetPriceAge)) {\n MessageLib.UpdateContractMaxAssetPriceAge memory m =\n MessageLib.deserializeUpdateContractMaxAssetPriceAge(payload);\n\n ShareClassDetails storage shareClass = _shareClass(poolId, scId);\n require(m.assetId != 0, UnknownAsset());\n\n (address asset, uint256 tokenId) = idToAsset(AssetId.wrap(m.assetId));\n shareClass.pricePoolPerAsset[asset][tokenId].maxAge = m.maxPriceAge;\n emit UpdateMaxAssetPriceAge(poolId, scId, asset, tokenId, m.maxPriceAge);\n } else if (kind == uint8(UpdateContractType.MaxSharePriceAge)) {\n MessageLib.UpdateContractMaxSharePriceAge memory m =\n MessageLib.deserializeUpdateContractMaxSharePriceAge(payload);\n\n ShareClassDetails storage shareClass = _shareClass(poolId, scId);\n\n shareClass.pricePoolPerShare.maxAge = m.maxPriceAge;\n emit UpdateMaxSharePriceAge(poolId, scId, m.maxPriceAge);\n } else {\n revert UnknownUpdateContractType();\n }\n }\n\n /// @inheritdoc IPoolManager\n function linkVault(PoolId poolId, ShareClassId scId, AssetId assetId, IBaseVault vault) public auth {\n _shareClass(poolId, scId);\n\n AssetIdKey memory assetIdKey = _idToAsset[assetId];\n\n IBaseRequestManager manager = vault.manager();\n manager.addVault(poolId, scId, vault, assetIdKey.asset, assetId);\n\n _vaultDetails[vault].isLinked = true;\n\n emit LinkVault(poolId, scId, assetIdKey.asset, assetIdKey.tokenId, vault);\n }\n\n /// @inheritdoc IPoolManager\n function unlinkVault(PoolId poolId, ShareClassId scId, AssetId assetId, IBaseVault vault) public auth {\n _shareClass(poolId, scId);\n\n AssetIdKey memory assetIdKey = _idToAsset[assetId];\n\n IBaseRequestManager manager = vault.manager();\n manager.removeVault(poolId, scId, vault, assetIdKey.asset, assetId);\n\n _vaultDetails[vault].isLinked = false;\n\n emit UnlinkVault(poolId, scId, assetIdKey.asset, assetIdKey.tokenId, vault);\n }\n\n /// @inheritdoc IPoolManager\n function deployVault(PoolId poolId, ShareClassId scId, AssetId assetId, IVaultFactory factory)\n public\n auth\n returns (IBaseVault)\n {\n ShareClassDetails storage shareClass = _shareClass(poolId, scId);\n require(vaultFactory[factory], InvalidFactory());\n\n // Rely investment manager on vault so it can mint tokens\n address[] memory vaultWards = new address[](0);\n\n // Deploy vault\n AssetIdKey memory assetIdKey = _idToAsset[assetId];\n IBaseVault vault = IVaultFactory(factory).newVault(\n poolId, scId, assetIdKey.asset, assetIdKey.tokenId, shareClass.shareToken, vaultWards\n );\n\n // Check whether asset is an ERC20 token wrapper\n (bool success, bytes memory data) =\n assetIdKey.asset.staticcall(abi.encodeWithSelector(IERC20Wrapper.underlying.selector));\n // On success, the returned 20 byte address is padded to 32 bytes\n bool isWrappedERC20 = success && data.length == 32;\n _vaultDetails[vault] = VaultDetails(assetId, assetIdKey.asset, assetIdKey.tokenId, isWrappedERC20, false);\n\n // NOTE - Reverting the manager approvals is not easy. We SHOULD do that if we phase-out a manager\n VaultKind vaultKind = _relyShareToken(vault, shareClass.shareToken);\n\n emit DeployVault(poolId, scId, assetIdKey.asset, assetIdKey.tokenId, factory, vault, vaultKind);\n return vault;\n }\n\n //----------------------------------------------------------------------------------------------\n // View methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IPoolManager\n function isPoolActive(PoolId poolId) public view returns (bool) {\n return pools[poolId].createdAt > 0;\n }\n\n /// @inheritdoc IPoolManager\n function shareToken(PoolId poolId, ShareClassId scId) public view returns (IShareToken) {\n ShareClassDetails storage shareClass = pools[poolId].shareClasses[scId];\n require(address(shareClass.shareToken) != address(0), UnknownToken());\n return shareClass.shareToken;\n }\n\n /// @inheritdoc IPoolManager\n function vaultDetails(IBaseVault vault) public view returns (VaultDetails memory details) {\n details = _vaultDetails[vault];\n require(details.asset != address(0), UnknownVault());\n }\n\n /// @inheritdoc IPoolManager\n function isLinked(PoolId, /* poolId */ ShareClassId, /* scId */ address, /* asset */ IBaseVault vault)\n public\n view\n returns (bool)\n {\n return _vaultDetails[vault].isLinked;\n }\n\n /// @inheritdoc IPoolManager\n function idToAsset(AssetId assetId) public view returns (address asset, uint256 tokenId) {\n AssetIdKey memory assetIdKey = _idToAsset[assetId];\n require(assetIdKey.asset != address(0), UnknownAsset());\n return (assetIdKey.asset, assetIdKey.tokenId);\n }\n\n /// @inheritdoc IPoolManager\n function assetToId(address asset, uint256 tokenId) public view returns (AssetId assetId) {\n assetId = _assetToId[asset][tokenId];\n require(assetId.raw() != 0, UnknownAsset());\n }\n\n /// @inheritdoc IPoolManager\n function priceAssetPerShare(PoolId poolId, ShareClassId scId, AssetId assetId, bool checkValidity)\n public\n view\n returns (D18 price)\n {\n (Price memory poolPerAsset, Price memory poolPerShare) = _pricesPoolPer(poolId, scId, assetId, checkValidity);\n\n price = PricingLib.priceAssetPerShare(poolPerShare.asPrice(), poolPerAsset.asPrice());\n }\n\n /// @inheritdoc IPoolManager\n function pricePoolPerShare(PoolId poolId, ShareClassId scId, bool checkValidity) public view returns (D18 price) {\n ShareClassDetails storage shareClass = _shareClass(poolId, scId);\n\n if (checkValidity) {\n require(shareClass.pricePoolPerShare.isValid(), InvalidPrice());\n }\n\n price = shareClass.pricePoolPerShare.asPrice();\n }\n\n /// @inheritdoc IPoolManager\n function pricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId, bool checkValidity)\n public\n view\n returns (D18 price)\n {\n (Price memory poolPerAsset,) = _pricesPoolPer(poolId, scId, assetId, false);\n\n if (checkValidity) {\n require(poolPerAsset.isValid(), InvalidPrice());\n }\n\n price = poolPerAsset.asPrice();\n }\n\n /// @inheritdoc IPoolManager\n function pricesPoolPer(PoolId poolId, ShareClassId scId, AssetId assetId, bool checkValidity)\n public\n view\n returns (D18 pricePoolPerAsset_, D18 pricePoolPerShare_)\n {\n (Price memory poolPerAsset, Price memory poolPerShare) = _pricesPoolPer(poolId, scId, assetId, checkValidity);\n return (poolPerAsset.asPrice(), poolPerShare.asPrice());\n }\n\n /// @inheritdoc IPoolManager\n function markersPricePoolPerShare(PoolId poolId, ShareClassId scId)\n external\n view\n returns (uint64 computedAt, uint64 maxAge, uint64 validUntil)\n {\n ShareClassDetails storage shareClass = _shareClass(poolId, scId);\n computedAt = shareClass.pricePoolPerShare.computedAt;\n maxAge = shareClass.pricePoolPerShare.maxAge;\n validUntil = shareClass.pricePoolPerShare.validUntil();\n }\n\n /// @inheritdoc IPoolManager\n function markersPricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId)\n external\n view\n returns (uint64 computedAt, uint64 maxAge, uint64 validUntil)\n {\n (Price memory poolPerAsset,) = _pricesPoolPer(poolId, scId, assetId, false);\n computedAt = poolPerAsset.computedAt;\n maxAge = poolPerAsset.maxAge;\n validUntil = poolPerAsset.validUntil();\n }\n\n //----------------------------------------------------------------------------------------------\n // Internal methods\n //----------------------------------------------------------------------------------------------\n\n function _pricesPoolPer(PoolId poolId, ShareClassId scId, AssetId assetId, bool checkValidity)\n internal\n view\n returns (Price memory poolPerAsset, Price memory poolPerShare)\n {\n ShareClassDetails storage shareClass = _shareClass(poolId, scId);\n\n (address asset, uint256 tokenId) = idToAsset(assetId);\n poolPerAsset = shareClass.pricePoolPerAsset[asset][tokenId];\n poolPerShare = shareClass.pricePoolPerShare;\n\n if (checkValidity) {\n require(poolPerAsset.isValid(), InvalidPrice());\n require(poolPerShare.isValid(), InvalidPrice());\n }\n }\n\n /// @dev Sets up approval permissions for pool, i.e. the pool escrow, the base vault manager and potentially a\n /// secondary manager (in case of partially sync vault)\n function _relyShareToken(IBaseVault vault, IShareToken shareToken_) internal returns (VaultKind) {\n IBaseRequestManager manager = vault.manager();\n IAuth(address(shareToken_)).rely(address(manager));\n\n // For sync deposit & async redeem vault, also repeat above for async manager\n VaultKind vaultKind = vault.vaultKind();\n if (vaultKind == VaultKind.SyncDepositAsyncRedeem) {\n IAuth(address(shareToken_)).rely(address(asyncRequestManager));\n }\n\n return vaultKind;\n }\n\n function _safeGetAssetDecimals(address asset, uint256 tokenId) private view returns (uint8) {\n bytes memory callData;\n\n if (tokenId == 0) {\n callData = abi.encodeWithSignature(\"decimals()\");\n } else {\n callData = abi.encodeWithSignature(\"decimals(uint256)\", tokenId);\n }\n\n (bool success, bytes memory data) = asset.staticcall(callData);\n require(success && data.length >= 32, AssetMissingDecimals());\n\n return abi.decode(data, (uint8));\n }\n\n function _isValidHook(address hook) internal view returns (bool) {\n (bool success, bytes memory data) =\n hook.staticcall(abi.encodeWithSelector(IERC165.supportsInterface.selector, type(IHook).interfaceId));\n\n return success && data.length == 32 && abi.decode(data, (bool));\n }\n\n function _shareClass(PoolId poolId, ShareClassId scId)\n internal\n view\n returns (ShareClassDetails storage shareClass)\n {\n shareClass = pools[poolId].shareClasses[scId];\n require(address(shareClass.shareToken) != address(0), ShareTokenDoesNotExist());\n }\n}\n" + }, + "src/vaults/SyncDepositVault.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IERC165} from \"src/misc/interfaces/IERC7575.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nimport {BaseVault, BaseAsyncRedeemVault, BaseSyncDepositVault} from \"src/vaults/BaseVaults.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\nimport {IAsyncRedeemManager} from \"src/vaults/interfaces/investments/IAsyncRedeemManager.sol\";\nimport {ISyncDepositManager} from \"src/vaults/interfaces/investments/ISyncDepositManager.sol\";\nimport {IBaseRequestManager} from \"src/vaults/interfaces/investments/IBaseRequestManager.sol\";\nimport {VaultKind} from \"src/vaults/interfaces/IBaseVaults.sol\";\n\n/// @title SyncDepositVault\n/// @notice Partially (a)synchronous Tokenized Vault implementation with synchronous deposits\n/// and asynchronous redemptions following ERC-7540.\n///\n/// @dev Each vault issues shares of Centrifuge share class tokens as restricted ERC-20 tokens\n/// against asset deposits based on the current share price.\ncontract SyncDepositVault is BaseSyncDepositVault, BaseAsyncRedeemVault {\n constructor(\n PoolId poolId_,\n ShareClassId scId_,\n address asset_,\n IShareToken token_,\n address root_,\n ISyncDepositManager syncDepositManager_,\n IAsyncRedeemManager asyncRedeemManager_\n )\n BaseVault(poolId_, scId_, asset_, token_, root_, syncDepositManager_)\n BaseSyncDepositVault(syncDepositManager_)\n BaseAsyncRedeemVault(asyncRedeemManager_)\n {}\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n function file(bytes32 what, address data) external override(BaseAsyncRedeemVault, BaseVault) auth {\n if (what == \"manager\") manager = IBaseRequestManager(data);\n else if (what == \"asyncRedeemManager\") asyncRedeemManager = IAsyncRedeemManager(data);\n else if (what == \"syncDepositManager\") syncDepositManager = ISyncDepositManager(data);\n else revert FileUnrecognizedParam();\n emit File(what, data);\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-165\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC165\n function supportsInterface(bytes4 interfaceId)\n public\n pure\n override(BaseAsyncRedeemVault, BaseSyncDepositVault)\n returns (bool)\n {\n return super.supportsInterface(interfaceId);\n }\n\n //----------------------------------------------------------------------------------------------\n // IBaseVault view\n //----------------------------------------------------------------------------------------------\n\n function vaultKind() public pure returns (VaultKind vaultKind_) {\n return VaultKind.SyncDepositAsyncRedeem;\n }\n}\n" + }, + "src/vaults/SyncRequestManager.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IERC165} from \"forge-std/interfaces/IERC165.sol\";\nimport {IERC7540Redeem} from \"src/misc/interfaces/IERC7540.sol\";\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {BytesLib} from \"src/misc/libraries/BytesLib.sol\";\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {IAuth} from \"src/misc/interfaces/IAuth.sol\";\nimport {d18, D18} from \"src/misc/types/D18.sol\";\n\nimport {MessageLib, UpdateContractType} from \"src/common/libraries/MessageLib.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {PricingLib} from \"src/common/libraries/PricingLib.sol\";\n\nimport {BaseRequestManager} from \"src/vaults/BaseRequestManager.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\nimport {IAsyncRedeemVault, IBaseVault, VaultKind} from \"src/vaults/interfaces/IBaseVaults.sol\";\nimport {IPoolManager, VaultDetails} from \"src/vaults/interfaces/IPoolManager.sol\";\nimport {IBalanceSheet} from \"src/vaults/interfaces/IBalanceSheet.sol\";\nimport {IBaseRequestManager} from \"src/vaults/interfaces/investments/IBaseRequestManager.sol\";\nimport {\n ISyncRequestManager,\n Prices,\n ISyncDepositValuation\n} from \"src/vaults/interfaces/investments/ISyncRequestManager.sol\";\nimport {IDepositManager} from \"src/vaults/interfaces/investments/IDepositManager.sol\";\nimport {ISyncDepositManager} from \"src/vaults/interfaces/investments/ISyncDepositManager.sol\";\nimport {IUpdateContract} from \"src/vaults/interfaces/IUpdateContract.sol\";\nimport {IEscrow} from \"src/vaults/interfaces/IEscrow.sol\";\nimport {IPoolEscrowProvider} from \"src/vaults/interfaces/factories/IPoolEscrowFactory.sol\";\nimport {IAsyncRedeemManager} from \"src/vaults/interfaces/investments/IAsyncRedeemManager.sol\";\n\n/// @title Sync Investment Manager\n/// @notice This is the main contract vaults interact with for\n/// both incoming and outgoing investment transactions.\ncontract SyncRequestManager is BaseRequestManager, ISyncRequestManager {\n using BytesLib for bytes;\n using MathLib for *;\n using CastLib for *;\n using MessageLib for *;\n\n IBalanceSheet public balanceSheet;\n\n mapping(PoolId => mapping(ShareClassId scId => ISyncDepositValuation)) public valuation;\n mapping(PoolId => mapping(ShareClassId scId => mapping(address asset => mapping(uint256 tokenId => uint128))))\n public maxReserve;\n\n constructor(IEscrow globalEscrow_, address root_, address deployer)\n BaseRequestManager(globalEscrow_, root_, deployer)\n {}\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IBaseRequestManager\n function file(bytes32 what, address data) external override(IBaseRequestManager, BaseRequestManager) auth {\n if (what == \"poolManager\") poolManager = IPoolManager(data);\n else if (what == \"balanceSheet\") balanceSheet = IBalanceSheet(data);\n else if (what == \"poolEscrowProvider\") poolEscrowProvider = IPoolEscrowProvider(data);\n else revert FileUnrecognizedParam();\n emit File(what, data);\n }\n\n /// @inheritdoc IUpdateContract\n function update(PoolId poolId, ShareClassId scId, bytes memory payload) external auth {\n uint8 kind = uint8(MessageLib.updateContractType(payload));\n\n if (kind == uint8(UpdateContractType.Valuation)) {\n MessageLib.UpdateContractValuation memory m = MessageLib.deserializeUpdateContractValuation(payload);\n\n require(address(poolManager.shareToken(poolId, scId)) != address(0), ShareTokenDoesNotExist());\n\n setValuation(poolId, scId, m.valuation.toAddress());\n } else if (kind == uint8(UpdateContractType.SyncDepositMaxReserve)) {\n MessageLib.UpdateContractSyncDepositMaxReserve memory m =\n MessageLib.deserializeUpdateContractSyncDepositMaxReserve(payload);\n\n require(address(poolManager.shareToken(poolId, scId)) != address(0), ShareTokenDoesNotExist());\n (address asset, uint256 tokenId) = poolManager.idToAsset(AssetId.wrap(m.assetId));\n\n setMaxReserve(poolId, scId, asset, tokenId, m.maxReserve);\n } else {\n revert UnknownUpdateContractType();\n }\n }\n\n /// @inheritdoc IBaseRequestManager\n function addVault(PoolId poolId, ShareClassId scId, IBaseVault vault_, address asset_, AssetId assetId)\n public\n override(BaseRequestManager, IBaseRequestManager)\n auth\n {\n super.addVault(poolId, scId, vault_, asset_, assetId);\n\n (, uint256 tokenId) = poolManager.idToAsset(assetId);\n setMaxReserve(poolId, scId, asset_, tokenId, type(uint128).max);\n\n VaultKind vaultKind_ = vault_.vaultKind();\n if (vaultKind_ == VaultKind.SyncDepositAsyncRedeem) {\n IAsyncRedeemManager asyncRequestManager = IAsyncRedeemVault(address(vault_)).asyncRedeemManager();\n require(address(asyncRequestManager) != address(0), SecondaryManagerDoesNotExist());\n asyncRequestManager.addVault(poolId, scId, vault_, asset_, assetId);\n }\n }\n\n /// @inheritdoc IBaseRequestManager\n function removeVault(PoolId poolId, ShareClassId scId, IBaseVault vault_, address asset_, AssetId assetId)\n public\n override(BaseRequestManager, IBaseRequestManager)\n auth\n {\n super.removeVault(poolId, scId, vault_, asset_, assetId);\n\n (, uint256 tokenId) = poolManager.idToAsset(assetId);\n delete maxReserve[poolId][scId][asset_][tokenId];\n\n VaultKind vaultKind_ = vault_.vaultKind();\n if (vaultKind_ == VaultKind.SyncDepositAsyncRedeem) {\n IAsyncRedeemManager asyncRequestManager = IAsyncRedeemVault(address(vault_)).asyncRedeemManager();\n require(address(asyncRequestManager) != address(0), SecondaryManagerDoesNotExist());\n asyncRequestManager.removeVault(poolId, scId, vault_, asset_, assetId);\n }\n }\n\n /// @inheritdoc ISyncRequestManager\n function setValuation(PoolId poolId, ShareClassId scId, address valuation_) public auth {\n valuation[poolId][scId] = ISyncDepositValuation(valuation_);\n\n emit SetValuation(poolId, scId, address(valuation_));\n }\n\n /// @inheritdoc ISyncRequestManager\n function setMaxReserve(PoolId poolId, ShareClassId scId, address asset, uint256 tokenId, uint128 maxReserve_)\n public\n auth\n {\n maxReserve[poolId][scId][asset][tokenId] = maxReserve_;\n\n emit SetMaxReserve(poolId, scId, asset, tokenId, maxReserve_);\n }\n\n //----------------------------------------------------------------------------------------------\n // Deposit handlers\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IDepositManager\n function mint(IBaseVault vault_, uint256 shares, address receiver, address owner)\n external\n auth\n returns (uint256 assets)\n {\n require(maxMint(vault_, owner) >= shares, ExceedsMaxMint());\n assets = previewMint(vault_, owner, shares);\n\n _issueShares(vault_, shares.toUint128(), receiver, owner, assets.toUint128());\n }\n\n /// @inheritdoc IDepositManager\n function deposit(IBaseVault vault_, uint256 assets, address receiver, address owner)\n external\n auth\n returns (uint256 shares)\n {\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n require(poolManager.isLinked(vault_.poolId(), vault_.scId(), vaultDetails.asset, vault_), AssetNotAllowed());\n\n require(maxDeposit(vault_, owner) >= assets, ExceedsMaxDeposit());\n shares = previewDeposit(vault_, owner, assets);\n\n _issueShares(vault_, shares.toUint128(), receiver, owner, assets.toUint128());\n }\n\n //----------------------------------------------------------------------------------------------\n // View methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc ISyncDepositManager\n function previewMint(IBaseVault vault_, address, /* sender */ uint256 shares)\n public\n view\n returns (uint256 assets)\n {\n return _shareToAssetAmount(vault_, shares, MathLib.Rounding.Up);\n }\n\n /// @inheritdoc ISyncDepositManager\n function previewDeposit(IBaseVault vault_, address, /* sender */ uint256 assets)\n public\n view\n returns (uint256 shares)\n {\n return convertToShares(vault_, assets);\n }\n\n /// @inheritdoc IDepositManager\n function maxMint(IBaseVault vault_, address /* owner */ ) public view returns (uint256) {\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n uint128 maxAssets = _maxDeposit(vault_.poolId(), vault_.scId(), vaultDetails.asset, vaultDetails.tokenId);\n return convertToShares(vault_, maxAssets);\n }\n\n /// @inheritdoc IDepositManager\n function maxDeposit(IBaseVault vault_, address /* owner */ ) public view returns (uint256) {\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n return _maxDeposit(vault_.poolId(), vault_.scId(), vaultDetails.asset, vaultDetails.tokenId);\n }\n\n /// @inheritdoc IBaseRequestManager\n function convertToShares(IBaseVault vault_, uint256 assets)\n public\n view\n override(IBaseRequestManager, BaseRequestManager)\n returns (uint256 shares)\n {\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n Prices memory prices_ = prices(vault_.poolId(), vault_.scId(), vaultDetails.assetId);\n\n return super._assetToShareAmount(\n vault_, vaultDetails, assets, prices_.poolPerAsset, prices_.poolPerShare, MathLib.Rounding.Down\n );\n }\n\n /// @inheritdoc IBaseRequestManager\n function convertToAssets(IBaseVault vault_, uint256 shares)\n public\n view\n override(IBaseRequestManager, BaseRequestManager)\n returns (uint256 assets)\n {\n return _shareToAssetAmount(vault_, shares, MathLib.Rounding.Down);\n }\n\n /// @inheritdoc ISyncDepositValuation\n function pricePoolPerShare(PoolId poolId, ShareClassId scId) public view returns (D18 price) {\n ISyncDepositValuation valuation_ = valuation[poolId][scId];\n\n if (address(valuation_) == address(0)) {\n price = poolManager.pricePoolPerShare(poolId, scId, true);\n } else {\n price = valuation_.pricePoolPerShare(poolId, scId);\n }\n }\n\n /// @inheritdoc ISyncRequestManager\n function prices(PoolId poolId, ShareClassId scId, AssetId assetId) public view returns (Prices memory priceData) {\n priceData.poolPerShare = pricePoolPerShare(poolId, scId);\n priceData.poolPerAsset = poolManager.pricePoolPerAsset(poolId, scId, assetId, true);\n priceData.assetPerShare = PricingLib.priceAssetPerShare(priceData.poolPerShare, priceData.poolPerAsset);\n }\n\n //----------------------------------------------------------------------------------------------\n // Internal\n //----------------------------------------------------------------------------------------------\n\n /// @dev Issues shares to the receiver and instruct the balance sheet\n // to react on the issuance and the updated holding.\n function _issueShares(IBaseVault vault_, uint128 shares, address receiver, address, /* owner */ uint128 assets)\n internal\n {\n PoolId poolId = vault_.poolId();\n ShareClassId scId = vault_.scId();\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n\n balanceSheet.overridePricePoolPerShare(poolId, scId, prices(poolId, scId, vaultDetails.assetId).poolPerShare);\n balanceSheet.issue(poolId, scId, receiver, shares);\n\n // Note deposit into the pool escrow, to make assets available for managers of the balance sheet\n // ERC-20 transfer is handled by the vault to the pool escrow afterwards\n balanceSheet.noteDeposit(poolId, scId, vaultDetails.asset, vaultDetails.tokenId, receiver, assets);\n }\n\n function _maxDeposit(PoolId poolId, ShareClassId scId, address asset, uint256 tokenId)\n internal\n view\n returns (uint128 maxDeposit_)\n {\n uint128 availableBalance = poolEscrowProvider.escrow(poolId).availableBalanceOf(scId, asset, tokenId);\n uint128 maxReserve_ = maxReserve[poolId][scId][asset][tokenId];\n\n if (maxReserve_ < availableBalance) {\n maxDeposit_ = 0;\n } else {\n maxDeposit_ = maxReserve_ - availableBalance;\n }\n }\n\n function _shareToAssetAmount(IBaseVault vault_, uint256 assets, MathLib.Rounding rounding)\n internal\n view\n returns (uint256 shares)\n {\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault_);\n Prices memory prices_ = prices(vault_.poolId(), vault_.scId(), vaultDetails.assetId);\n return super._shareToAssetAmount(\n vault_, vaultDetails, assets, prices_.poolPerAsset, prices_.poolPerShare, rounding\n );\n }\n}\n" + }, + "src/vaults/VaultRouter.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\nimport {Multicall, IMulticall} from \"src/misc/Multicall.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {SafeTransferLib} from \"src/misc/libraries/SafeTransferLib.sol\";\nimport {CastLib} from \"src/misc/libraries/CastLib.sol\";\nimport {IERC20, IERC20Permit, IERC20Wrapper} from \"src/misc/interfaces/IERC20.sol\";\nimport {IERC7540Deposit} from \"src/misc/interfaces/IERC7540.sol\";\nimport {Recoverable} from \"src/misc/Recoverable.sol\";\n\nimport {IGateway} from \"src/common/interfaces/IGateway.sol\";\nimport {IMessageDispatcher} from \"src/common/interfaces/IMessageDispatcher.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nimport {IAsyncVault, IBaseVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\nimport {IVaultRouter} from \"src/vaults/interfaces/IVaultRouter.sol\";\nimport {IPoolManager, VaultDetails} from \"src/vaults/interfaces/IPoolManager.sol\";\nimport {IEscrow} from \"src/vaults/interfaces/IEscrow.sol\";\nimport {BaseSyncDepositVault} from \"src/vaults/BaseVaults.sol\";\n\n/// @title VaultRouter\n/// @notice This is a helper contract, designed to be the entrypoint for EOAs.\n/// It removes the need to know about all other contracts and simplifies the way to interact with the protocol.\n/// It also adds the need to fully pay for each step of the transaction execution. VaultRouter allows\n/// the caller to execute multiple function into a single transaction by taking advantage of\n/// the multicall functionality which batches message calls into a single one.\n/// @dev It is critical to ensure that at the end of any transaction, no funds remain in the\n/// VaultRouter. Any funds that do remain are at risk of being taken by other users.\ncontract VaultRouter is Auth, Multicall, Recoverable, IVaultRouter {\n using CastLib for address;\n\n /// @dev Requests for Centrifuge pool are non-fungible and all have ID = 0\n uint256 private constant REQUEST_ID = 0;\n\n IEscrow public immutable escrow;\n IGateway public immutable gateway;\n IPoolManager public immutable poolManager;\n IMessageDispatcher public immutable messageDispatcher;\n\n /// @inheritdoc IVaultRouter\n mapping(address controller => mapping(IBaseVault vault => uint256 amount)) public lockedRequests;\n\n constructor(\n address escrow_,\n IGateway gateway_,\n IPoolManager poolManager_,\n IMessageDispatcher messageDispatcher_,\n address deployer\n ) Auth(deployer) {\n escrow = IEscrow(escrow_);\n gateway = gateway_;\n poolManager = poolManager_;\n messageDispatcher = messageDispatcher_;\n }\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IMulticall\n /// @notice performs a multicall but all message sent in the process will be batched\n function multicall(bytes[] calldata data) public payable override(Multicall, IMulticall) {\n bool wasBatching = gateway.isBatching();\n if (!wasBatching) {\n gateway.startBatching();\n gateway.payTransaction{value: msg.value}(msg.sender);\n }\n\n super.multicall(data);\n\n if (!wasBatching) {\n gateway.endBatching();\n }\n }\n\n //----------------------------------------------------------------------------------------------\n // Enable interactions\n //----------------------------------------------------------------------------------------------\n\n function enable(IBaseVault vault) public payable protected {\n vault.setEndorsedOperator(msg.sender, true);\n }\n\n function disable(IBaseVault vault) external payable protected {\n vault.setEndorsedOperator(msg.sender, false);\n }\n\n //----------------------------------------------------------------------------------------------\n // Deposit\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IVaultRouter\n function requestDeposit(IAsyncVault vault, uint256 amount, address controller, address owner)\n external\n payable\n protected\n {\n require(owner == msg.sender || owner == address(this), InvalidOwner());\n\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault);\n if (owner == address(this)) {\n _approveMax(vaultDetails.asset, address(vault));\n }\n\n _pay();\n vault.requestDeposit(amount, controller, owner);\n }\n\n /// @inheritdoc IVaultRouter\n function deposit(BaseSyncDepositVault vault, uint256 assets, address receiver, address owner)\n external\n payable\n protected\n {\n require(owner == msg.sender || owner == address(this), InvalidOwner());\n require(!vault.supportsInterface(type(IERC7540Deposit).interfaceId), NonSyncDepositVault());\n\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault);\n SafeTransferLib.safeTransferFrom(vaultDetails.asset, owner, address(this), assets);\n _approveMax(vaultDetails.asset, address(vault));\n\n _pay();\n vault.deposit(assets, receiver);\n }\n\n /// @inheritdoc IVaultRouter\n function lockDepositRequest(IBaseVault vault, uint256 amount, address controller, address owner)\n public\n payable\n protected\n {\n require(owner == msg.sender || owner == address(this), InvalidOwner());\n require(vault.supportsInterface(type(IERC7540Deposit).interfaceId), NonAsyncVault());\n\n lockedRequests[controller][vault] += amount;\n\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault);\n SafeTransferLib.safeTransferFrom(vaultDetails.asset, owner, address(escrow), amount);\n\n emit LockDepositRequest(vault, controller, owner, msg.sender, amount);\n }\n\n /// @inheritdoc IVaultRouter\n function enableLockDepositRequest(IBaseVault vault, uint256 amount) external payable protected {\n enable(vault);\n\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault);\n\n uint256 assetBalance;\n assetBalance = IERC20(vaultDetails.asset).balanceOf(msg.sender);\n\n if (vaultDetails.isWrapper && assetBalance < amount) {\n wrap(vaultDetails.asset, amount, address(this), msg.sender);\n lockDepositRequest(vault, amount, msg.sender, address(this));\n } else {\n lockDepositRequest(vault, amount, msg.sender, msg.sender);\n }\n }\n\n /// @inheritdoc IVaultRouter\n function unlockDepositRequest(IBaseVault vault, address receiver) external payable protected {\n uint256 lockedRequest = lockedRequests[msg.sender][vault];\n require(lockedRequest != 0, NoLockedBalance());\n lockedRequests[msg.sender][vault] = 0;\n\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault);\n escrow.authTransferTo(vaultDetails.asset, receiver, lockedRequest);\n\n emit UnlockDepositRequest(vault, msg.sender, receiver);\n }\n\n /// @inheritdoc IVaultRouter\n function executeLockedDepositRequest(IAsyncVault vault, address controller) external payable protected {\n uint256 lockedRequest = lockedRequests[controller][vault];\n require(lockedRequest != 0, NoLockedRequest());\n lockedRequests[controller][vault] = 0;\n\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault);\n escrow.authTransferTo(vaultDetails.asset, address(this), lockedRequest);\n\n _pay();\n _approveMax(vaultDetails.asset, address(vault));\n vault.requestDeposit(lockedRequest, controller, address(this));\n emit ExecuteLockedDepositRequest(vault, controller, msg.sender);\n }\n\n /// @inheritdoc IVaultRouter\n function claimDeposit(IAsyncVault vault, address receiver, address controller) external payable protected {\n _canClaim(vault, receiver, controller);\n uint256 maxMint = vault.maxMint(controller);\n vault.mint(maxMint, receiver, controller);\n }\n\n /// @inheritdoc IVaultRouter\n function cancelDepositRequest(IAsyncVault vault) external payable protected {\n _pay();\n vault.cancelDepositRequest(REQUEST_ID, msg.sender);\n }\n\n /// @inheritdoc IVaultRouter\n function claimCancelDepositRequest(IAsyncVault vault, address receiver, address controller)\n external\n payable\n protected\n {\n _canClaim(vault, receiver, controller);\n vault.claimCancelDepositRequest(REQUEST_ID, receiver, controller);\n }\n\n //----------------------------------------------------------------------------------------------\n // Redeem\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IVaultRouter\n function requestRedeem(IAsyncVault vault, uint256 amount, address controller, address owner)\n external\n payable\n protected\n {\n require(owner == msg.sender || owner == address(this), InvalidOwner());\n _pay();\n vault.requestRedeem(amount, controller, owner);\n }\n\n /// @inheritdoc IVaultRouter\n function claimRedeem(IBaseVault vault, address receiver, address controller) external payable protected {\n _canClaim(vault, receiver, controller);\n uint256 maxWithdraw = vault.maxWithdraw(controller);\n\n VaultDetails memory vaultDetails = poolManager.vaultDetails(vault);\n if (vaultDetails.isWrapper && controller != msg.sender) {\n // Auto-unwrap if permissionlessly claiming for another controller\n vault.withdraw(maxWithdraw, address(this), controller);\n unwrap(vaultDetails.asset, maxWithdraw, receiver);\n } else {\n vault.withdraw(maxWithdraw, receiver, controller);\n }\n }\n\n /// @inheritdoc IVaultRouter\n function cancelRedeemRequest(IAsyncVault vault) external payable protected {\n _pay();\n vault.cancelRedeemRequest(REQUEST_ID, msg.sender);\n }\n\n /// @inheritdoc IVaultRouter\n function claimCancelRedeemRequest(IAsyncVault vault, address receiver, address controller)\n external\n payable\n protected\n {\n _canClaim(vault, receiver, controller);\n vault.claimCancelRedeemRequest(REQUEST_ID, receiver, controller);\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-20 permits & wrapping\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IVaultRouter\n function permit(address asset, address spender, uint256 assets, uint256 deadline, uint8 v, bytes32 r, bytes32 s)\n external\n payable\n protected\n {\n try IERC20Permit(asset).permit(msg.sender, spender, assets, deadline, v, r, s) {} catch {}\n }\n\n function wrap(address wrapper, uint256 amount, address receiver, address owner) public payable protected {\n require(owner == msg.sender || owner == address(this), InvalidOwner());\n address underlying = IERC20Wrapper(wrapper).underlying();\n\n amount = MathLib.min(amount, IERC20(underlying).balanceOf(owner));\n require(amount != 0, ZeroBalance());\n SafeTransferLib.safeTransferFrom(underlying, owner, address(this), amount);\n\n _approveMax(underlying, wrapper);\n require(IERC20Wrapper(wrapper).depositFor(receiver, amount), WrapFailed());\n }\n\n function unwrap(address wrapper, uint256 amount, address receiver) public payable protected {\n amount = MathLib.min(amount, IERC20(wrapper).balanceOf(address(this)));\n require(amount != 0, ZeroBalance());\n\n require(IERC20Wrapper(wrapper).withdrawTo(receiver, amount), UnwrapFailed());\n }\n\n //----------------------------------------------------------------------------------------------\n // View methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IVaultRouter\n function getVault(PoolId poolId, ShareClassId scId, address asset) external view returns (address) {\n return IPoolManager(poolManager).shareToken(poolId, scId).vault(asset);\n }\n\n /// @inheritdoc IVaultRouter\n function estimate(uint16 centrifugeId, bytes calldata payload) external view returns (uint256) {\n return messageDispatcher.estimate(centrifugeId, payload);\n }\n\n /// @inheritdoc IVaultRouter\n function hasPermissions(IBaseVault vault, address controller) external view returns (bool) {\n return vault.isPermissioned(controller);\n }\n\n /// @inheritdoc IVaultRouter\n function isEnabled(IBaseVault vault, address controller) public view returns (bool) {\n return vault.isOperator(controller, address(this));\n }\n\n /// @notice Gives the max approval to `to` for spending the given `asset` if not already approved.\n /// @dev Assumes that `type(uint256).max` is large enough to never have to increase the allowance again.\n function _approveMax(address asset, address spender) internal {\n if (IERC20(asset).allowance(address(this), spender) == 0) {\n SafeTransferLib.safeApprove(asset, spender, type(uint256).max);\n }\n }\n\n /// @notice Send native tokens to the gateway for transaction payment if it's not in a multicall.\n function _pay() internal {\n if (!gateway.isBatching()) {\n gateway.payTransaction{value: msg.value}(msg.sender);\n }\n }\n\n /// @notice Ensures msg.sender is either the controller, or can permissionlessly claim\n /// on behalf of the controller.\n function _canClaim(IBaseVault vault, address receiver, address controller) internal view {\n require(controller == msg.sender || (controller == receiver && isEnabled(vault, controller)), InvalidSender());\n }\n}\n" + }, + "src/vaults/factories/AsyncVaultFactory.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nimport {AsyncVault} from \"src/vaults/AsyncVault.sol\";\nimport {IVaultFactory} from \"src/vaults/interfaces/factories/IVaultFactory.sol\";\nimport {IPoolEscrowProvider} from \"src/vaults/interfaces/factories/IPoolEscrowFactory.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\nimport {IAsyncRequestManager} from \"src/vaults/interfaces/investments/IAsyncRequestManager.sol\";\nimport {IBaseVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\n\n/// @title ERC7540 Vault Factory\n/// @dev Utility for deploying new vault contracts\ncontract AsyncVaultFactory is Auth, IVaultFactory {\n address public immutable root;\n IAsyncRequestManager public immutable asyncRequestManager;\n\n constructor(address root_, IAsyncRequestManager asyncRequestManager_, address deployer) Auth(deployer) {\n root = root_;\n asyncRequestManager = asyncRequestManager_;\n }\n\n /// @inheritdoc IVaultFactory\n function newVault(\n PoolId poolId,\n ShareClassId scId,\n address asset,\n uint256 tokenId,\n IShareToken token,\n address[] calldata wards_\n ) public auth returns (IBaseVault) {\n require(tokenId == 0, UnsupportedTokenId());\n AsyncVault vault = new AsyncVault(poolId, scId, asset, token, root, asyncRequestManager);\n\n vault.rely(root);\n vault.rely(address(asyncRequestManager));\n uint256 wardsCount = wards_.length;\n for (uint256 i; i < wardsCount; i++) {\n vault.rely(wards_[i]);\n }\n\n vault.deny(address(this));\n return vault;\n }\n}\n" + }, + "src/vaults/factories/PoolEscrowFactory.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\n\nimport {IPoolEscrowProvider, IPoolEscrowFactory} from \"src/vaults/interfaces/factories/IPoolEscrowFactory.sol\";\nimport {IPoolEscrow} from \"src/vaults/interfaces/IEscrow.sol\";\nimport {PoolEscrow} from \"src/vaults/Escrow.sol\";\n\ncontract PoolEscrowFactory is Auth, IPoolEscrowFactory {\n address public immutable root;\n\n address public gateway;\n address public poolManager;\n address public balanceSheet;\n address public asyncRequestManager;\n\n constructor(address root_, address deployer) Auth(deployer) {\n root = root_;\n }\n\n /// @inheritdoc IPoolEscrowFactory\n function file(bytes32 what, address data) external auth {\n if (what == \"poolManager\") poolManager = data;\n else if (what == \"gateway\") gateway = data;\n else if (what == \"balanceSheet\") balanceSheet = data;\n else if (what == \"asyncRequestManager\") asyncRequestManager = data;\n else revert FileUnrecognizedParam();\n emit File(what, data);\n }\n\n /// @inheritdoc IPoolEscrowFactory\n function newEscrow(PoolId poolId) public auth returns (IPoolEscrow) {\n PoolEscrow escrow_ = new PoolEscrow{salt: bytes32(uint256(poolId.raw()))}(poolId, address(this));\n\n escrow_.rely(root);\n escrow_.rely(gateway);\n escrow_.rely(poolManager);\n escrow_.rely(balanceSheet);\n escrow_.rely(asyncRequestManager);\n\n escrow_.deny(address(this));\n\n emit DeployPoolEscrow(poolId, address(escrow_));\n return IPoolEscrow(escrow_);\n }\n\n /// @inheritdoc IPoolEscrowProvider\n function escrow(PoolId poolId) external view returns (IPoolEscrow) {\n bytes32 salt = bytes32(uint256(poolId.raw()));\n bytes32 hash = keccak256(\n abi.encodePacked(\n bytes1(0xff),\n address(this),\n salt,\n keccak256(abi.encodePacked(type(PoolEscrow).creationCode, abi.encode(poolId, address(this))))\n )\n );\n\n return IPoolEscrow(address(uint160(uint256(hash))));\n }\n}\n" + }, + "src/vaults/factories/SyncDepositVaultFactory.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nimport {SyncDepositVault} from \"src/vaults/SyncDepositVault.sol\";\nimport {IVaultFactory} from \"src/vaults/interfaces/factories/IVaultFactory.sol\";\nimport {IAsyncRedeemManager} from \"src/vaults/interfaces/investments/IAsyncRedeemManager.sol\";\nimport {ISyncDepositManager} from \"src/vaults/interfaces/investments/ISyncDepositManager.sol\";\nimport {IPoolEscrowProvider} from \"src/vaults/interfaces/factories/IPoolEscrowFactory.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\nimport {IBaseVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\n\n/// @title Sync Vault Factory\n/// @dev Utility for deploying new vault contracts\ncontract SyncDepositVaultFactory is Auth, IVaultFactory {\n address public immutable root;\n ISyncDepositManager public immutable syncDepositManager;\n IAsyncRedeemManager public immutable asyncRedeemManager;\n\n constructor(\n address root_,\n ISyncDepositManager syncDepositManager_,\n IAsyncRedeemManager asyncRedeemManager_,\n address deployer\n ) Auth(deployer) {\n root = root_;\n syncDepositManager = syncDepositManager_;\n asyncRedeemManager = asyncRedeemManager_;\n }\n\n /// @inheritdoc IVaultFactory\n function newVault(\n PoolId poolId,\n ShareClassId scId,\n address asset,\n uint256 tokenId,\n IShareToken token,\n address[] calldata wards_\n ) public auth returns (IBaseVault) {\n require(tokenId == 0, UnsupportedTokenId());\n SyncDepositVault vault =\n new SyncDepositVault(poolId, scId, asset, token, root, syncDepositManager, asyncRedeemManager);\n\n vault.rely(root);\n vault.rely(address(syncDepositManager));\n vault.rely(address(asyncRedeemManager));\n\n uint256 wardsCount = wards_.length;\n for (uint256 i; i < wardsCount; i++) {\n vault.rely(wards_[i]);\n }\n\n vault.deny(address(this));\n return vault;\n }\n}\n" + }, + "src/vaults/factories/TokenFactory.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {Auth} from \"src/misc/Auth.sol\";\n\nimport {ShareToken} from \"src/vaults/token/ShareToken.sol\";\nimport {ITokenFactory} from \"src/vaults/interfaces/factories/ITokenFactory.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\n\n/// @title Share Token Factory\n/// @dev Utility for deploying new share class token contracts\n/// Ensures the addresses are deployed at a deterministic address\n/// based on the pool id and share class id.\ncontract TokenFactory is Auth, ITokenFactory {\n address public immutable root;\n\n constructor(address _root, address deployer) Auth(deployer) {\n root = _root;\n }\n\n /// @inheritdoc ITokenFactory\n function newToken(\n string memory name,\n string memory symbol,\n uint8 decimals,\n bytes32 salt,\n address[] calldata tokenWards\n ) public auth returns (IShareToken) {\n ShareToken token = new ShareToken{salt: salt}(decimals);\n\n token.file(\"name\", name);\n token.file(\"symbol\", symbol);\n\n token.rely(root);\n uint256 wardsCount = tokenWards.length;\n for (uint256 i; i < wardsCount; i++) {\n token.rely(tokenWards[i]);\n }\n token.deny(address(this));\n\n return token;\n }\n\n /// @inheritdoc ITokenFactory\n function getAddress(uint8 decimals, bytes32 salt) external view returns (address) {\n bytes32 hash = keccak256(\n abi.encodePacked(\n bytes1(0xff),\n address(this),\n salt,\n keccak256(abi.encodePacked(type(ShareToken).creationCode, abi.encode(decimals)))\n )\n );\n\n return address(uint160(uint256(hash)));\n }\n}\n" + }, + "src/vaults/interfaces/IBalanceSheet.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {D18, d18} from \"src/misc/types/D18.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\n\nstruct QueueAmount {\n // Issuances of shares / deposits of assets\n uint128 increase;\n // Revocations of shares / withdraws of assets\n uint128 decrease;\n}\n\ninterface IBalanceSheet {\n // --- Events ---\n event File(bytes32 indexed what, address data);\n event UpdateManager(PoolId indexed poolId, address who, bool canManage);\n event Withdraw(\n PoolId indexed poolId,\n ShareClassId indexed scId,\n address asset,\n uint256 tokenId,\n address receiver,\n uint128 amount,\n D18 pricePoolPerAsset\n );\n event Deposit(\n PoolId indexed poolId,\n ShareClassId indexed scId,\n address asset,\n uint256 tokenId,\n address provider,\n uint128 amount,\n D18 pricePoolPerAsset\n );\n event Issue(PoolId indexed poolId, ShareClassId indexed scId, address to, D18 pricePoolPerShare, uint128 shares);\n event Revoke(PoolId indexed poolId, ShareClassId indexed scId, address from, D18 pricePoolPerShare, uint128 shares);\n\n // --- Errors ---\n error FileUnrecognizedParam();\n error CannotTransferFromEndorsedContract();\n\n /// @notice Overloaded increase with asset transfer\n function deposit(PoolId poolId, ShareClassId scId, address asset, uint256 tokenId, address provider, uint128 amount)\n external;\n\n function noteDeposit(\n PoolId poolId,\n ShareClassId scId,\n address asset,\n uint256 tokenId,\n address provider,\n uint128 amount\n ) external;\n\n function withdraw(\n PoolId poolId,\n ShareClassId scId,\n address asset,\n uint256 tokenId,\n address receiver,\n uint128 amount\n ) external;\n\n function issue(PoolId poolId, ShareClassId scId, address to, uint128 shares) external;\n\n function revoke(PoolId poolId, ShareClassId scId, address from, uint128 shares) external;\n\n function noteRevoke(PoolId poolId, ShareClassId scId, address from, uint128 shares) external;\n\n function transferSharesFrom(PoolId poolId, ShareClassId scId, address from, address to, uint256 amount) external;\n\n function overridePricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId, D18 value) external;\n\n function overridePricePoolPerShare(PoolId poolId, ShareClassId scId, D18 value) external;\n}\n" + }, + "src/vaults/interfaces/IBaseVaults.sol": { + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.5.0;\n\nenum VaultKind {\n /// @dev Refers to AsyncVault\n Async,\n /// @dev not yet supported\n Sync,\n /// @dev Refers to SyncDepositVault\n SyncDepositAsyncRedeem\n}\n\nimport {IERC7575, IERC165} from \"src/misc/interfaces/IERC7575.sol\";\nimport {\n IERC7540Operator,\n IERC7714,\n IERC7741,\n IERC7540Redeem,\n IERC7887Redeem,\n IERC7887Deposit,\n IERC7540Deposit\n} from \"src/misc/interfaces/IERC7540.sol\";\nimport {IRecoverable} from \"src/misc/interfaces/IRecoverable.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nimport {IBaseRequestManager} from \"src/vaults/interfaces/investments/IBaseRequestManager.sol\";\nimport {IAsyncRedeemManager} from \"src/vaults/interfaces/investments/IAsyncRedeemManager.sol\";\n\n/// @notice Interface for the all vault contracts\n/// @dev Must be implemented by all vaults\ninterface IBaseVault is IERC7540Operator, IERC7741, IERC7714, IERC7575, IRecoverable {\n error FileUnrecognizedParam();\n error NotEndorsed();\n error CannotSetSelfAsOperator();\n error ExpiredAuthorization();\n error AlreadyUsedAuthorization();\n error InvalidAuthorization();\n error InvalidController();\n error InsufficientBalance();\n error RequestRedeemFailed();\n error TransferFromFailed();\n\n event File(bytes32 indexed what, address data);\n\n /// @notice Identifier of the Centrifuge pool\n function poolId() external view returns (PoolId);\n\n /// @notice Identifier of the share class of the Centrifuge pool\n function scId() external view returns (ShareClassId);\n\n /// @notice Set msg.sender as operator of owner, to `approved` status\n /// @dev MUST be called by endorsed sender\n function setEndorsedOperator(address owner, bool approved) external;\n\n /// @notice Returns the base investment manager contract handling the vault.\n /// @dev This naming MUST NOT change due to requirements of legacy vaults (v2)\n /// @return IBaseRequestManager The address of the manager contract that is between vault and gateway\n function manager() external view returns (IBaseRequestManager);\n\n /// @notice Checks whether the vault is partially (a)synchronous.\n ///\n /// @return vaultKind_ The kind of the vault\n function vaultKind() external view returns (VaultKind vaultKind_);\n}\n\n/**\n * @title IAsyncRedeemVault\n * @dev This is the specific set of interfaces used by the Centrifuge implementation of ERC7540,\n * as a fully asynchronous Vault, with cancellation support, and authorize operator signature support.\n */\ninterface IAsyncRedeemVault is IERC7540Redeem, IERC7887Redeem, IBaseVault {\n event RedeemClaimable(address indexed controller, uint256 indexed requestId, uint256 assets, uint256 shares);\n event CancelRedeemClaimable(address indexed controller, uint256 indexed requestId, uint256 shares);\n\n /// @notice Callback when a redeem Request is triggered externally;\n function onRedeemRequest(address controller, address owner, uint256 shares) external;\n\n /// @notice Callback when a redeem Request becomes claimable\n function onRedeemClaimable(address owner, uint256 assets, uint256 shares) external;\n\n /// @notice Callback when a claim redeem Request becomes claimable\n function onCancelRedeemClaimable(address owner, uint256 shares) external;\n\n /// @notice Retrieve the asynchronous redeem manager\n function asyncRedeemManager() external view returns (IAsyncRedeemManager);\n}\n\ninterface IAsyncVault is IERC7540Deposit, IERC7887Deposit, IAsyncRedeemVault {\n event DepositClaimable(address indexed controller, uint256 indexed requestId, uint256 assets, uint256 shares);\n event CancelDepositClaimable(address indexed controller, uint256 indexed requestId, uint256 assets);\n\n error InvalidOwner();\n error RequestDepositFailed();\n\n /// @notice Callback when a deposit Request becomes claimable\n function onDepositClaimable(address owner, uint256 assets, uint256 shares) external;\n\n /// @notice Callback when a claim deposit Request becomes claimable\n function onCancelDepositClaimable(address owner, uint256 assets) external;\n}\n" + }, + "src/vaults/interfaces/IEscrow.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IRecoverable} from \"src/misc/Recoverable.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\n/// @title Escrow for holding assets\ninterface IEscrow {\n // --- Events ---\n /// @notice Emitted when an authTransferTo is made\n /// @dev Needed as allowances increase attack surface\n event AuthTransferTo(address indexed asset, uint256 indexed tokenId, address reciver, uint256 value);\n\n /// @notice Emitted when the escrow has insufficient balance for an action - virtual or actual balance\n error InsufficientBalance(address asset, uint256 tokenId, uint256 value, uint256 balance);\n\n /// @notice\n function authTransferTo(address asset, uint256 tokenId, address receiver, uint256 value) external;\n\n /// @notice\n function authTransferTo(address asset, address receiver, uint256 value) external;\n}\n\nstruct Holding {\n uint128 total;\n uint128 reserved;\n}\n\n/// @title PerPoolEscrow separating funds by pool and share class\ninterface IPoolEscrow is IEscrow, IRecoverable {\n // --- Events ---\n /// @notice Emitted when a deposit is made\n /// @param asset The address of the deposited asset\n /// @param tokenId The id of the asset - 0 for ERC20\n /// @param poolId The id of the pool\n /// @param scId The id of the share class\n /// @param value The amount deposited\n event Deposit(\n address indexed asset, uint256 indexed tokenId, PoolId indexed poolId, ShareClassId scId, uint128 value\n );\n\n /// @notice Emitted when an amount is reserved\n /// @param asset The address of the reserved asset\n /// @param tokenId The id of the asset - 0 for ERC20\n /// @param poolId The id of the pool\n /// @param scId The id of the share class\n /// @param value The delta amount reserved\n /// @param value The new absolute amount reserved\n event IncreaseReserve(\n address indexed asset,\n uint256 indexed tokenId,\n PoolId indexed poolId,\n ShareClassId scId,\n uint256 delta,\n uint128 value\n );\n\n /// @notice Emitted when an amount is unreserved\n /// @param asset The address of the reserved asset\n /// @param tokenId The id of the asset - 0 for ERC20\n /// @param poolId The id of the pool\n /// @param scId The id of the share class\n /// @param value The delta amount unreserved\n /// @param value The new absolute amount reserved\n event DecreaseReserve(\n address indexed asset,\n uint256 indexed tokenId,\n PoolId indexed poolId,\n ShareClassId scId,\n uint256 delta,\n uint128 value\n );\n\n /// @notice Emitted when a withdraw is made\n /// @param asset The address of the withdrawn asset\n /// @param tokenId The id of the asset - 0 for ERC20\n /// @param poolId The id of the pool\n /// @param scId The id of the share class\n /// @param value The amount withdrawn\n event Withdraw(\n address indexed asset, uint256 indexed tokenId, PoolId indexed poolId, ShareClassId scId, uint128 value\n );\n\n // --- Errors ---\n /// @notice Dispatched when the balance of the escrow did not increase sufficiently\n error InsufficientDeposit();\n\n /// @notice Dispatched when the outstanding reserved amount is insufficient for the decrease\n error InsufficientReservedAmount();\n\n // --- Functions ---\n /// @notice Deposits `value` of `asset` in underlying `poolId` and given `scId`\n ///\n /// @dev NOTE: Must ensure balance sufficiency, i.e. that the depositing amount does not exceed the balance of\n /// escrow\n ///\n /// @param scId The id of the share class\n /// @param asset The address of the asset to be deposited\n /// @param tokenId The id of the asset - 0 for ERC20\n /// @param value The amount to deposit\n function deposit(ShareClassId scId, address asset, uint256 tokenId, uint128 value) external;\n\n /// @notice Withdraws `value` of `asset` in underlying `poolId` and given `scId`\n /// @dev MUST ensure that reserved amounts are not withdrawn\n /// @param scId The id of the share class\n /// @param asset The address of the asset to be withdrawn\n /// @param tokenId The id of the asset - 0 for ERC20\n /// @param value The amount to withdraw\n function withdraw(ShareClassId scId, address asset, uint256 tokenId, uint128 value) external;\n\n /// @notice Increases the reserved amount of `value` for `asset` in underlying `poolId` and given `scId`\n /// @dev MUST prevent the reserved amount from being withdrawn\n /// @param scId The id of the share class\n /// @param asset The address of the asset to be reserved\n /// @param tokenId The id of the asset - 0 for ERC20\n /// @param value The amount to reserve\n function reserveIncrease(ShareClassId scId, address asset, uint256 tokenId, uint128 value) external;\n\n /// @notice Decreases the reserved amount of `value` for `asset` in underlying `poolId` and given `scId`\n /// @dev MUST fail if `value` is greater than the current reserved amount\n /// @param scId The id of the share class\n /// @param asset The address of the asset to be reserved\n /// @param tokenId The id of the asset - 0 for ERC20\n /// @param value The amount to decrease\n function reserveDecrease(ShareClassId scId, address asset, uint256 tokenId, uint128 value) external;\n\n /// @notice Provides the available balance of `asset` in underlying `poolId` and given `scId`\n /// @dev MUST return the balance minus the reserved amount\n /// @param scId The id of the share class\n /// @param asset The address of the asset to be checked\n /// @param tokenId The id of the asset - 0 for ERC20\n /// @return The available balance\n function availableBalanceOf(ShareClassId scId, address asset, uint256 tokenId) external view returns (uint128);\n}\n" + }, + "src/vaults/interfaces/IPoolManager.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {D18, d18} from \"src/misc/types/D18.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\n\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\nimport {IVaultFactory} from \"src/vaults/interfaces/factories/IVaultFactory.sol\";\nimport {IBaseVault, VaultKind} from \"src/vaults/interfaces/IBaseVaults.sol\";\n\n/// @dev Centrifuge pools\nstruct Pool {\n uint256 createdAt;\n mapping(ShareClassId scId => ShareClassDetails) shareClasses;\n}\n\n/// @dev Each Centrifuge pool is associated to 1 or more shar classes\nstruct ShareClassDetails {\n IShareToken shareToken;\n /// @dev Each share class has an individual price per share class unit in pool denomination (POOL_UNIT/SHARE_UNIT)\n Price pricePoolPerShare;\n /// @dev Each share class can have multiple vaults deployed,\n /// multiple vaults can be linked to the same asset.\n /// A vault in this storage DOES NOT mean the vault can be used\n mapping(address asset => mapping(uint256 tokenId => IBaseVault[])) vaults;\n /// @dev For each share class, we store the price per pool unit in asset denomination (POOL_UNIT/ASSET_UNIT)\n mapping(address asset => mapping(uint256 tokenId => Price)) pricePoolPerAsset;\n}\n\n/// @dev Price struct that contains a price, the timestamp at which it was computed and the max age of the price.\nstruct Price {\n uint128 price;\n uint64 computedAt;\n uint64 maxAge;\n}\n\n/// @dev Checks if a price is valid. Returns false if price is 0 or computedAt is 0. Otherwise checks for block\n/// timestamp <= computedAt + maxAge\nfunction isValid(Price memory price) view returns (bool) {\n if (price.computedAt != 0 && price.price != 0) {\n return block.timestamp <= price.validUntil();\n } else {\n return false;\n }\n}\n\n/// @dev Computes the timestamp until the price is valid. Saturates at uint64.MAX.\nfunction validUntil(Price memory price) pure returns (uint64) {\n unchecked {\n uint64 validUntil_ = price.computedAt + price.maxAge;\n if (validUntil_ < price.computedAt) {\n return type(uint64).max;\n }\n return validUntil_;\n }\n}\n\n/// @dev Retrieves the price as an D18 from the struct\nfunction asPrice(Price memory price) pure returns (D18) {\n return d18(price.price);\n}\n\nusing {isValid, asPrice, validUntil} for Price global;\n\nstruct VaultDetails {\n /// @dev AssetId of the asset\n AssetId assetId;\n /// @dev Address of the asset\n address asset;\n /// @dev TokenId of the asset - zero if asset is ERC20, non-zero if asset is ERC6909\n uint256 tokenId;\n /// @dev Whether this wrapper conforms to the IERC20Wrapper interface\n bool isWrapper;\n /// @dev Whether the vault is linked to a share class atm\n bool isLinked;\n}\n\nstruct AssetIdKey {\n /// @dev The address of the asset\n address asset;\n /// @dev The ERC6909 token id or 0, if the underlying asset is an ERC20\n uint256 tokenId;\n}\n\ninterface IPoolManager {\n event File(bytes32 indexed what, address data);\n event RegisterAsset(\n AssetId indexed assetId,\n address indexed asset,\n uint256 indexed tokenId,\n string name,\n string symbol,\n uint8 decimals\n );\n event File(bytes32 indexed what, address factory, bool status);\n event AddPool(PoolId indexed poolId);\n event AddShareClass(PoolId indexed poolId, ShareClassId indexed scId, IShareToken token);\n event DeployVault(\n PoolId indexed poolId,\n ShareClassId indexed scId,\n address indexed asset,\n uint256 tokenId,\n IVaultFactory factory,\n IBaseVault vault,\n VaultKind kind\n );\n event PriceUpdate(\n PoolId indexed poolId,\n ShareClassId indexed scId,\n address indexed asset,\n uint256 tokenId,\n uint256 price,\n uint64 computedAt\n );\n event PriceUpdate(PoolId indexed poolId, ShareClassId indexed scId, uint256 price, uint64 computedAt);\n event TransferShares(\n uint16 centrifugeId,\n PoolId indexed poolId,\n ShareClassId indexed scId,\n address indexed sender,\n bytes32 destinationAddress,\n uint128 amount\n );\n event UpdateContract(PoolId indexed poolId, ShareClassId indexed scId, address target, bytes payload);\n event LinkVault(\n PoolId indexed poolId, ShareClassId indexed scId, address indexed asset, uint256 tokenId, IBaseVault vault\n );\n event UnlinkVault(\n PoolId indexed poolId, ShareClassId indexed scId, address indexed asset, uint256 tokenId, IBaseVault vault\n );\n event UpdateMaxSharePriceAge(PoolId indexed poolId, ShareClassId indexed scId, uint64 maxPriceAge);\n event UpdateMaxAssetPriceAge(\n PoolId indexed poolId, ShareClassId indexed scId, address indexed asset, uint256 tokenId, uint64 maxPriceAge\n );\n\n error FileUnrecognizedParam();\n error TooFewDecimals();\n error TooManyDecimals();\n error PoolAlreadyAdded();\n error InvalidPool();\n error ShareClassAlreadyRegistered();\n error InvalidHook();\n error OldMetadata();\n error CannotSetOlderPrice();\n error OldHook();\n error UnknownVault();\n error UnknownAsset();\n error MalformedVaultUpdateMessage();\n error UnknownToken();\n error InvalidFactory();\n error InvalidPrice();\n error AssetMissingDecimals();\n error ShareTokenDoesNotExist();\n error LocalTransferNotAllowed();\n error CrossChainTransferNotAllowed();\n error ShareTokenTransferFailed();\n error TransferFromFailed();\n\n /// @notice Returns the asset address and tokenId associated with a given asset id.\n /// @dev Reverts if asset id does not exist\n ///\n /// @param assetId The underlying internal uint128 assetId.\n /// @return asset The address of the asset linked to the given asset id.\n /// @return tokenId The token id corresponding to the asset, i.e. zero if ERC20 or non-zero if ERC6909.\n function idToAsset(AssetId assetId) external view returns (address asset, uint256 tokenId);\n\n /// @notice Returns assetId given the asset address and tokenId.\n /// @dev Reverts if asset id does not exist\n ///\n /// @param asset The address of the asset linked to the given asset id.\n /// @param tokenId The token id corresponding to the asset, i.e. zero if ERC20 or non-zero if ERC6909.\n /// @return assetId The underlying internal uint128 assetId.\n function assetToId(address asset, uint256 tokenId) external view returns (AssetId assetId);\n\n /// @notice Updates a contract parameter\n /// @param what Accepts a bytes32 representation of 'gateway', 'investmentManager', 'tokenFactory',\n /// 'vaultFactory', or 'gasService'\n function file(bytes32 what, address data) external;\n\n /// @notice Updates a contract parameter\n /// @param what Accepts a bytes32 representation of 'vaultFactory'\n function file(bytes32 what, address factory, bool status) external;\n\n /// @notice transfers share class tokens to a cross-chain recipient address\n /// @dev To transfer to evm chains, pad a 20 byte evm address with 12 bytes of 0\n /// @param centrifugeId The destination chain id\n /// @param poolId The centrifuge pool id\n /// @param scId The share class id\n /// @param receiver A bytes32 representation of the receiver address\n /// @param amount The amount of tokens to transfer\n function transferShares(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bytes32 receiver, uint128 amount)\n external\n payable;\n\n /// @notice Registers an ERC-20 or ERC-6909 asset in another chain.\n /// @dev `decimals()` MUST return a `uint8` value between 2 and 18.\n /// @dev `name()` and `symbol()` MAY return no values.\n ///\n /// @param centrifugeId The centrifuge id of chain to where the shares are transferred\n /// @param asset The address of the asset to be registered\n /// @param tokenId The token id corresponding to the asset, i.e. zero if ERC20 or non-zero if ERC6909.\n /// @return assetId The underlying internal uint128 assetId.\n function registerAsset(uint16 centrifugeId, address asset, uint256 tokenId)\n external\n payable\n returns (AssetId assetId);\n\n /// @notice Deploys a new vault\n ///\n /// @param poolId The pool id\n /// @param scId The share class id\n /// @param assetId The asset id for which we want to deploy a vault\n /// @param factory The address of the corresponding vault factory\n /// @return address The address of the deployed vault\n function deployVault(PoolId poolId, ShareClassId scId, AssetId assetId, IVaultFactory factory)\n external\n returns (IBaseVault);\n\n /// @notice Links a deployed vault to the given pool, share class and asset.\n ///\n /// @param poolId The pool id\n /// @param scId The share class id\n /// @param assetId The asset id for which we want to deploy a vault\n /// @param vault The address of the deployed vault\n function linkVault(PoolId poolId, ShareClassId scId, AssetId assetId, IBaseVault vault) external;\n\n /// @notice Removes the link between a vault and the given pool, share class and asset.\n ///\n /// @param poolId The pool id\n /// @param scId The share class id\n /// @param assetId The asset id for which we want to deploy a vault\n /// @param vault The address of the deployed vault\n function unlinkVault(PoolId poolId, ShareClassId scId, AssetId assetId, IBaseVault vault) external;\n\n /// @notice Returns whether the given pool id is active\n function isPoolActive(PoolId poolId) external view returns (bool);\n\n /// @notice Returns the share class token for a given pool and share class id.\n /// @dev Reverts if share class does not exists\n ///\n /// @param poolId The pool id\n /// @param scId The share class id\n /// @return address The address of the share token\n function shareToken(PoolId poolId, ShareClassId scId) external view returns (IShareToken);\n\n /// @notice Function to get the details of a vault\n /// @dev Reverts if vault does not exist\n ///\n /// @param vault The address of the vault to be checked for\n /// @return details The details of the vault including the underlying asset address, token id, asset id\n function vaultDetails(IBaseVault vault) external view returns (VaultDetails memory details);\n\n /// @notice Checks whether a given asset-vault pair is eligible for investing into a share class of a pool\n ///\n /// @param poolId The pool id\n /// @param scId The share class id\n /// @param asset The address of the asset\n /// @param vault The address of the vault\n /// @return bool Whether vault is to a share class\n function isLinked(PoolId poolId, ShareClassId scId, address asset, IBaseVault vault) external view returns (bool);\n\n /// @notice Returns the price per share for a given pool, share class, asset, and asset id. The provided price is\n /// defined as ASSET_UNIT/SHARE_UNIT.\n /// @dev Conditionally checks if price is valid.\n ///\n /// @dev NOTE: Should never be used for calculating amounts due to precision loss. Instead, please refer to\n /// conversion relying on pricePoolPerShare and pricePoolPerAsset. See PricingLib for more information.\n ///\n /// @param poolId The pool id\n /// @param scId The share class id\n /// @param assetId The asset id for which we want to know the ASSET_UNIT/SHARE_UNIT price\n /// @param checkValidity Whether to check if the price is valid\n /// @return price The asset price per share\n function priceAssetPerShare(PoolId poolId, ShareClassId scId, AssetId assetId, bool checkValidity)\n external\n view\n returns (D18 price);\n\n /// @notice Returns the price per share for a given pool and share class. The Provided price is defined as\n /// POOL_UNIT/SHARE_UNIT.\n /// @dev Conditionally checks if price is valid.\n ///\n /// @param poolId The pool id\n /// @param scId The share class id\n /// @param checkValidity Whether to check if the price is valid\n /// @return price The pool price per share\n function pricePoolPerShare(PoolId poolId, ShareClassId scId, bool checkValidity)\n external\n view\n returns (D18 price);\n\n /// @notice Returns the price per asset for a given pool, share class and the underlying asset id. The Provided\n /// price is defined as POOL_UNIT/ASSET_UNIT.\n /// @dev Conditionally checks if price is valid.\n ///\n /// @param poolId The pool id\n /// @param scId The share class id\n /// @param assetId The asset id for which we want to know the POOL_UNIT/ASSET_UNIT.\n /// @param checkValidity Whether to check if the price is valid\n /// @return price The pool price per asset unit\n function pricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId, bool checkValidity)\n external\n view\n returns (D18 price);\n\n /// @notice Returns the both prices per pool for a given pool, share class and the underlying asset id. The Provided\n /// prices is defined as POOL_UNIT/ASSET_UNIT and POOL_UNIT/SHARE_UNIT.\n /// @dev Conditionally checks if prices are valid.\n ///\n /// @param poolId The pool id\n /// @param scId The share class id\n /// @param assetId The asset id for which we want to know pool price per asset\n /// @param checkValidity Whether to check if the prices are valid\n /// @return pricePoolPerAsset The pool price per asset unit, i.e. POOL_UNIT/ASSET_UNIT\n /// @return pricePoolPerShare The pool price per share unit, i.e. POOL_UNIT/SHARE_UNIT\n function pricesPoolPer(PoolId poolId, ShareClassId scId, AssetId assetId, bool checkValidity)\n external\n view\n returns (D18 pricePoolPerAsset, D18 pricePoolPerShare);\n\n /// @notice Returns the age related markers for a share class price\n ///\n /// @param poolId The pool id\n /// @param scId The share class id\n /// @return computedAt The timestamp when this price was computed\n /// @return maxAge The maximum age this price is allowed to have\n /// @return validUntil The timestamp until this price is valid\n function markersPricePoolPerShare(PoolId poolId, ShareClassId scId)\n external\n view\n returns (uint64 computedAt, uint64 maxAge, uint64 validUntil);\n\n /// @notice Returns the age related markers for an asset price\n ///\n /// @param poolId The pool id\n /// @param scId The share class id\n /// @param assetId The asset id for which we want to know pool price per asset\n /// @return computedAt The timestamp when this price was computed\n /// @return maxAge The maximum age this price is allowed to have\n /// @return validUntil The timestamp until this price is valid\n function markersPricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId)\n external\n view\n returns (uint64 computedAt, uint64 maxAge, uint64 validUntil);\n}\n" + }, + "src/vaults/interfaces/IUpdateContract.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\n\ninterface IUpdateContract {\n error UnknownUpdateContractType();\n\n /// @notice Triggers an update on the target contract.\n /// @param poolId The centrifuge pool id\n /// @param scId The share class id\n /// @param payload The payload to be processed by the target address\n function update(PoolId poolId, ShareClassId scId, bytes calldata payload) external;\n}\n" + }, + "src/vaults/interfaces/IVaultRouter.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\nimport {IMulticall} from \"src/misc/interfaces/IMulticall.sol\";\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {IBaseVault, IAsyncVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\nimport {BaseSyncDepositVault} from \"src/vaults/BaseVaults.sol\";\n\ninterface IVaultRouter is IMulticall {\n // --- Events ---\n event LockDepositRequest(\n IBaseVault indexed vault, address indexed controller, address indexed owner, address sender, uint256 amount\n );\n event UnlockDepositRequest(IBaseVault indexed vault, address indexed controller, address indexed receiver);\n event ExecuteLockedDepositRequest(IBaseVault indexed vault, address indexed controller, address sender);\n\n error InvalidOwner();\n error NoLockedBalance();\n error NoLockedRequest();\n error ZeroBalance();\n error WrapFailed();\n error UnwrapFailed();\n error InvalidSender();\n error NonSyncDepositVault();\n error NonAsyncVault();\n\n /// @notice Check how much of the `vault`'s asset is locked for the current `controller`.\n /// @dev This is a getter method\n function lockedRequests(address controller, IBaseVault vault) external view returns (uint256 amount);\n\n // --- Manage permissionless claiming ---\n /// @notice Enable permissionless claiming\n /// @dev After this is called, anyone can claim tokens to msg.sender.\n /// Even any requests submitted directly to the vault (not through the VaultRouter) will be\n /// permissionlessly claimable through the VaultRouter, until `disable()` is called.\n function enable(IBaseVault vault) external payable;\n\n /// @notice Disable permissionless claiming\n function disable(IBaseVault vault) external payable;\n\n // --- Deposit ---\n /// @notice Check `IERC7540Deposit.requestDeposit`.\n /// @dev This adds a mandatory prepayment for all the costs that will incur during the transaction.\n /// The caller must call `VaultRouter.estimate` to get estimates how much the deposit will cost.\n ///\n /// @param vault The vault to deposit into\n /// @param amount Check @param IERC7540Deposit.requestDeposit.assets\n /// @param controller Check @param IERC7540Deposit.requestDeposit.controller\n /// @param owner Check @param IERC7540Deposit.requestDeposit.owner\n function requestDeposit(IAsyncVault vault, uint256 amount, address controller, address owner) external payable;\n\n /// @notice Check `IERC4626.deposit`.\n /// @dev This adds a mandatory prepayment for all the costs that will incur during the transaction.\n /// The caller must call `VaultRouter.estimate` to get estimates how much the deposit will cost.\n ///\n /// @param vault The vault to deposit into\n /// @param assets Check @param IERC4626.deposit.assets\n /// @param receiver Check @param IERC4626.deposit.receiver\n /// @param owner User from which to transfer the assets, either msg.sender or the VaultRouter\n function deposit(BaseSyncDepositVault vault, uint256 assets, address receiver, address owner) external payable;\n\n /// @notice Locks `amount` of `vault`'s asset in an escrow before actually sending a deposit LockDepositRequest\n /// There are users that would like to interact with the protocol but don't have permissions yet. They can\n /// lock the funds they would like to deposit beforehand.\n /// Once permissions are granted, anyone can deposit on\n /// their behalf by calling `executeLockedDepositRequest`.\n ///\n /// Example: DAO with onchain governance, that wants to invest their treasury\n /// The process that doesn't include calling this method is as follows:\n ///\n /// 1. The DAO signs the legal agreements for the pool => no onchain action,\n /// but only after this the issuer can call update_member to add them as a whitelisted investor\n /// 2. Call `requestDeposit` to lock funds\n /// 3. After the pool has fulfilled their request, call `deposit` to claim their share class tokens\n ///\n ///\n /// With the new router function the steps are as follows:\n ///\n /// 1. DAO signs the legal agreement + calls `openLockDepositRequest` in 1 governance proposal\n ///\n /// 2. Issuer then gives them permissions, then calls `executeLockDepositFunds` for them,\n /// then fulfills the request, then calls `claimDeposit` for them\n ///\n /// @dev For initial interaction better use `openLockDepositRequest` which includes some of the message calls\n /// that the caller must do execute before calling `lockDepositRequest`\n ///\n /// @param vault The address of the vault to invest in\n /// @param amount Amount to invest\n /// @param controller Address of the owner of the position\n /// @param owner Where the funds to be deposited will be take from\n function lockDepositRequest(IBaseVault vault, uint256 amount, address controller, address owner) external payable;\n\n /// @notice Helper method to lock a deposit request, and enable permissionless claiming of that vault in 1 call.\n /// @dev It starts interaction with the vault by calling `open`.\n /// Vaults support assets that are wrapped one. When user calls this method\n /// and the vault's asset is a wrapped one, first the balance of the wrapped asset is checked.\n /// If balance >= `amount`, then this asset is used\n /// else amount is treat as an underlying asset one and it is wrapped.\n /// @param vault Address of the vault\n /// @param amount Amount to be deposited\n function enableLockDepositRequest(IBaseVault vault, uint256 amount) external payable;\n\n /// @notice Unlocks all deposited assets of the current caller for a given vault\n ///\n /// @param vault Address of the vault for which funds were locked\n /// @param receiver Address of the received of the unlocked funds\n function unlockDepositRequest(IBaseVault vault, address receiver) external payable;\n\n /// @notice After the controller is given permissions, anyone can call this method and\n /// actually request a deposit with the locked funds on the behalf of the `controller`\n /// @param vault The vault for which funds are locked\n /// @param controller Owner of the deposit position\n function executeLockedDepositRequest(IAsyncVault vault, address controller) external payable;\n\n /// @notice Check IERC7540Deposit.mint\n /// @param vault Address of the vault\n /// @param receiver Check IERC7540Deposit.mint.receiver\n /// @param controller Check IERC7540Deposit.mint.owner\n function claimDeposit(IAsyncVault vault, address receiver, address controller) external payable;\n\n // --- Redeem ---\n /// @notice Check `IERC7887Deposit.cancelDepositRequest`.\n /// @dev This adds a mandatory prepayment for all the costs that will incur during the transaction.\n /// The caller must call `VaultRouter.estimate` to get estimates how much the deposit will cost.\n ///\n /// @param vault The vault where the deposit was initiated\n function cancelDepositRequest(IAsyncVault vault) external payable;\n\n /// @notice Check IERC7887Deposit.claimCancelDepositRequest\n ///\n /// @param vault Address of the vault\n /// @param receiver Check IERC7887Deposit.claimCancelDepositRequest.receiver\n /// @param controller Check IERC7887Deposit.claimCancelDepositRequest.controller\n function claimCancelDepositRequest(IAsyncVault vault, address receiver, address controller) external payable;\n\n // --- Redeem ---\n /// @notice Check `IERC7540Redeem.requestRedeem`.\n /// @dev This adds a mandatory prepayment for all the costs that will incur during the transaction.\n /// The caller must call `VaultRouter.estimate` to get estimates how much the deposit will cost.\n ///\n /// @param vault The vault to deposit into\n /// @param amount Check @param IERC7540Redeem.requestRedeem.shares\n /// @param controller Check @param IERC7540Redeem.requestRedeem.controller\n /// @param owner Check @param IERC7540Redeem.requestRedeem.owner\n function requestRedeem(IAsyncVault vault, uint256 amount, address controller, address owner) external payable;\n\n /// @notice Check IERC7575.withdraw\n /// @dev If the underlying vault asset is a wrapped one,\n /// `VaultRouter.unwrap` is called and the unwrapped\n /// asset is sent to the receiver\n /// @param vault Address of the vault\n /// @param receiver Check IERC7575.withdraw.receiver\n /// @param controller Check IERC7575.withdraw.owner\n function claimRedeem(IBaseVault vault, address receiver, address controller) external payable;\n\n /// @notice Check `IERC7887Redeem.cancelRedeemRequest`.\n /// @dev This adds a mandatory prepayment for all the costs that will incur during the transaction.\n /// The caller must call `VaultRouter.estimate` to get estimates how much the deposit will cost.\n ///\n /// @param vault The vault where the deposit was initiated\n function cancelRedeemRequest(IAsyncVault vault) external payable;\n\n /// @notice Check IERC7887Redeem.claimableCancelRedeemRequest\n ///\n /// @param vault Address of the vault\n /// @param receiver Check IERC7887Redeem.claimCancelRedeemRequest.receiver\n /// @param controller Check IERC7887Redeem.claimCancelRedeemRequest.controller\n function claimCancelRedeemRequest(IAsyncVault vault, address receiver, address controller) external payable;\n\n // --- ERC20 permit ---\n /// @notice Check IERC20.permit\n function permit(address asset, address spender, uint256 assets, uint256 deadline, uint8 v, bytes32 r, bytes32 s)\n external\n payable;\n\n // --- ERC20 wrapping ---\n /// @notice There are vault which underlying asset is actuall a wrapped one.\n ///\n /// @param wrapper The address of the wrapper\n /// @param amount Amount to be wrapped\n /// @param receiver Receiver of the wrapped tokens\n /// @param owner The address from which `amount` is taken from\n function wrap(address wrapper, uint256 amount, address receiver, address owner) external payable;\n\n /// @notice There are vault which underlying asset is actuall a wrapped one.\n /// @dev Wrapped tokens need to be held by the VaultRouter to be unwrapped.\n /// @param wrapper The address of the wrapper\n /// @param amount Amount to be wrapped\n /// @param receiver Receiver of the unwrapped tokens\n function unwrap(address wrapper, uint256 amount, address receiver) external payable;\n\n // --- View Methods ---\n /// @notice Check IPoolManager.getVault\n function getVault(PoolId poolId, ShareClassId scId, address asset) external view returns (address);\n\n /// @notice Check IGateway.estimate\n /// If the destination and source chain ID are the same, this will always return 0.\n /// @param centrifugeId destination chain\n function estimate(uint16 centrifugeId, bytes calldata payload) external view returns (uint256 amount);\n\n /// @notice Called to check if `user` has permissions on `vault` to execute requests\n ///\n /// @param vault Address of the `vault` the `user` wants to operate on\n /// @param user Address of the `user` that will operates on the `vault`\n /// @return Whether `user` has permissions to operate on `vault`\n function hasPermissions(IBaseVault vault, address user) external view returns (bool);\n\n /// @notice Returns whether the controller has called `enable()` for the given `vault`\n function isEnabled(IBaseVault vault, address controller) external view returns (bool);\n}\n" + }, + "src/vaults/interfaces/factories/IPoolEscrowFactory.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\n\nimport {IPoolEscrow} from \"src/vaults/interfaces/IEscrow.sol\";\n\ninterface IPoolEscrowProvider {\n /// @notice Returns the deterministic address of an escrow contract based on a given pool id wrapped into the\n /// corresponding interface.\n ///\n /// @dev Does not check, whether the escrow was already deployed.\n function escrow(PoolId poolId) external view returns (IPoolEscrow);\n}\n\ninterface IPoolEscrowFactory is IPoolEscrowProvider {\n event DeployPoolEscrow(PoolId indexed poolId, address indexed escrow);\n event File(bytes32 what, address data);\n\n error FileUnrecognizedParam();\n error EscrowAlreadyDeployed();\n\n /// @notice Deploys new escrow and returns it.\n /// @dev All share classes of a pool are represented by the same escrow contract.\n ///\n /// @param poolId Id of the pool this escrow is deployed for\n /// @return IPoolEscrow The the newly deployed escrow contract\n function newEscrow(PoolId poolId) external returns (IPoolEscrow);\n\n /// @notice Updates contract parameters of type address.\n function file(bytes32 what, address data) external;\n}\n" + }, + "src/vaults/interfaces/factories/ITokenFactory.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\n\ninterface ITokenFactory {\n /// @notice Used to deploy new share class tokens.\n /// @dev In order to have the same address on different EVMs `salt` should be used\n /// during creationg process.\n /// @param name Name of the new token.\n /// @param symbol Symbol of the new token.\n /// @param decimals Decimals of the new token.\n /// @param salt Salt used for deterministic deployments.\n /// @param tokenWards Address which can call methods behind authorized only.\n function newToken(\n string memory name,\n string memory symbol,\n uint8 decimals,\n bytes32 salt,\n address[] calldata tokenWards\n ) external returns (IShareToken);\n\n /// @notice Returns the predicted address (using CREATE2)\n function getAddress(uint8 decimals, bytes32 salt) external view returns (address);\n}\n" + }, + "src/vaults/interfaces/factories/IVaultFactory.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\nimport {IPoolEscrow} from \"src/vaults/interfaces/IEscrow.sol\";\nimport {IBaseVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\n\ninterface IVaultFactory {\n error UnsupportedTokenId();\n\n /// @notice Deploys new vault for `poolId`, `scId` and `asset`.\n ///\n /// @param poolId Id of the pool. Id is one of the already supported pools.\n /// @param scId Id of the share class token. Id is one of the already supported share class tokens.\n /// @param asset Address of the underlying asset that is getting deposited inside the pool.\n /// @param asset Token id of the underlying asset that is getting deposited inside the pool. I.e. zero if asset\n /// corresponds to ERC20 or non-zero if asset corresponds to ERC6909.\n /// @param token Address of the share class token that is getting issues against the deposited asset.\n /// @param wards_ Address which can call methods behind authorized only.\n function newVault(\n PoolId poolId,\n ShareClassId scId,\n address asset,\n uint256 tokenId,\n IShareToken token,\n address[] calldata wards_\n ) external returns (IBaseVault);\n}\n" + }, + "src/vaults/interfaces/investments/IAsyncDepositManager.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IDepositManager} from \"src/vaults/interfaces/investments/IDepositManager.sol\";\nimport {IBaseVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\n\ninterface IAsyncDepositManager is IDepositManager {\n /// @notice Requests assets deposit. Vaults have to request investments from Centrifuge before\n /// shares can be minted. The deposit requests are added to the order book\n /// on the corresponding CP instance. Once the next epoch is executed on the corresponding CP instance,\n /// vaults can\n /// proceed with share payouts in case the order got fulfilled.\n /// @dev The assets required to fulfill the deposit request have to be locked and are transferred from the\n /// owner to the escrow, even though the share payout can only happen after epoch execution.\n /// The receiver becomes the owner of deposit request fulfillment.\n /// @param source Deprecated\n function requestDeposit(IBaseVault vault, uint256 assets, address receiver, address owner, address source)\n external\n returns (bool);\n\n /// @notice Requests the cancellation of a pending deposit request. Vaults have to request the\n /// cancellation of outstanding requests from Centrifuge before actual assets can be unlocked and\n /// transferred\n /// to the owner.\n /// While users have outstanding cancellation requests no new deposit requests can be submitted.\n /// Once the next epoch is executed on the corresponding CP instance, vaults can proceed with asset payouts\n /// if orders could be cancelled successfully.\n /// @dev The cancellation request might fail in case the pending deposit order already got fulfilled on\n /// Centrifuge.\n /// @param source Deprecated\n function cancelDepositRequest(IBaseVault vault, address owner, address source) external;\n\n /// @notice Processes owner's deposit request cancellation after the epoch has been executed on the corresponding CP\n /// instance and the\n /// deposit order cancellation has been successfully processed (partial fulfillment possible).\n /// Assets are transferred from the escrow to the receiver.\n /// @dev The assets required to fulfill the claim have already been reserved for the owner in escrow on\n /// fulfillCancelDepositRequest.\n function claimCancelDepositRequest(IBaseVault vault, address receiver, address owner)\n external\n returns (uint256 assets);\n\n /// @notice Indicates whether a user has pending deposit requests and returns the total deposit request asset\n /// request value.\n function pendingDepositRequest(IBaseVault vault, address user) external view returns (uint256 assets);\n\n /// @notice Indicates whether a user has pending deposit request cancellations.\n function pendingCancelDepositRequest(IBaseVault vault, address user) external view returns (bool isPending);\n\n /// @notice Indicates whether a user has claimable deposit request cancellation and returns the total claim\n /// value in assets.\n function claimableCancelDepositRequest(IBaseVault vault, address user) external view returns (uint256 assets);\n}\n" + }, + "src/vaults/interfaces/investments/IAsyncRedeemManager.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IRedeemManager} from \"src/vaults/interfaces/investments/IRedeemManager.sol\";\nimport {IBaseVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\n\ninterface IAsyncRedeemManager is IRedeemManager {\n /// @notice Requests share redemption. Vaults have to request redemptions\n /// from Centrifuge before actual asset payouts can be done. The redemption\n /// requests are added to the order book on the corresponding CP instance. Once the next epoch is\n /// executed on the corresponding CP instance, vaults can proceed with asset payouts\n /// in case the order got fulfilled.\n /// @dev The shares required to fulfill the redemption request have to be locked and are transferred from the\n /// owner to the escrow, even though the asset payout can only happen after epoch execution.\n /// The receiver becomes the owner of redeem request fulfillment.\n /// @param source Deprecated\n function requestRedeem(IBaseVault vault, uint256 shares, address receiver, address owner, address source)\n external\n returns (bool);\n\n /// @notice Requests the cancellation of an pending redeem request. Vaults have to request the\n /// cancellation of outstanding requests from Centrifuge before actual shares can be unlocked and\n /// transferred to the owner.\n /// While users have outstanding cancellation requests no new redeem requests can be submitted (exception:\n /// trigger through governance).\n /// Once the next epoch is executed on the corresponding CP instance, vaults can proceed with share payouts\n /// if the orders could be cancelled successfully.\n /// @dev The cancellation request might fail in case the pending redeem order already got fulfilled on\n /// Centrifuge.\n function cancelRedeemRequest(IBaseVault vault, address owner, address source) external;\n\n /// @notice Processes owner's redeem request cancellation after the epoch has been executed on the corresponding CP\n /// instance and the\n /// redeem order cancellation has been successfully processed (partial fulfillment possible).\n /// Shares are transferred from the escrow to the receiver.\n /// @dev The shares required to fulfill the claim have already been reserved for the owner in escrow on\n /// fulfillCancelRedeemRequest.\n /// Receiver has to pass all the share token restrictions in order to receive the shares.\n function claimCancelRedeemRequest(IBaseVault vault, address receiver, address owner)\n external\n returns (uint256 shares);\n\n /// @notice Indicates whether a user has pending redeem requests and returns the total share request value.\n function pendingRedeemRequest(IBaseVault vault, address user) external view returns (uint256 shares);\n\n /// @notice Indicates whether a user has pending redeem request cancellations.\n function pendingCancelRedeemRequest(IBaseVault vault, address user) external view returns (bool isPending);\n\n /// @notice Indicates whether a user has claimable redeem request cancellation and returns the total claim\n /// value in shares.\n function claimableCancelRedeemRequest(IBaseVault vault, address user) external view returns (uint256 shares);\n}\n" + }, + "src/vaults/interfaces/investments/IAsyncRequestManager.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IRequestManagerGatewayHandler} from \"src/common/interfaces/IGatewayHandlers.sol\";\n\nimport {IAsyncDepositManager} from \"src/vaults/interfaces/investments/IAsyncDepositManager.sol\";\nimport {IAsyncRedeemManager} from \"src/vaults/interfaces/investments/IAsyncRedeemManager.sol\";\nimport {IBaseVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\n\n/// @dev Vault requests and deposit/redeem bookkeeping per user\nstruct AsyncInvestmentState {\n /// @dev Shares that can be claimed using `mint()`\n uint128 maxMint;\n /// @dev Assets that can be claimed using `withdraw()`\n uint128 maxWithdraw;\n /// @dev Weighted average price of deposits, used to convert maxMint to maxDeposit\n /// @dev Represents priceAssetPerShare, i.e. ASSET_UNIT/SHARE_UNIT\n uint256 depositPrice;\n /// @dev Weighted average price of redemptions, used to convert maxWithdraw to maxRedeem\n /// @dev Represents priceAssetPerShare, i.e. ASSET_UNIT/SHARE_UNIT\n uint256 redeemPrice;\n /// @dev Remaining deposit request in assets\n uint128 pendingDepositRequest;\n /// @dev Remaining redeem request in shares\n uint128 pendingRedeemRequest;\n /// @dev Assets that can be claimed using `claimCancelDepositRequest()`\n uint128 claimableCancelDepositRequest;\n /// @dev Shares that can be claimed using `claimCancelRedeemRequest()`\n uint128 claimableCancelRedeemRequest;\n /// @dev Indicates whether the depositRequest was requested to be cancelled\n bool pendingCancelDepositRequest;\n /// @dev Indicates whether the redeemRequest was requested to be cancelled\n bool pendingCancelRedeemRequest;\n}\n\ninterface IAsyncRequestManager is IAsyncDepositManager, IAsyncRedeemManager, IRequestManagerGatewayHandler {\n error ZeroAmountNotAllowed();\n error TransferNotAllowed();\n error CancellationIsPending();\n error NoPendingRequest();\n error ShareTokenAmountIsZero();\n error FailedRedeemRequest();\n error ExceedsDepositLimits();\n error ShareTokenTransferFailed();\n error ExceedsMaxRedeem();\n error ExceedsRedeemLimits();\n\n /// @notice Returns the investment state\n function investments(IBaseVault vaultAddr, address investor)\n external\n view\n returns (\n uint128 maxMint,\n uint128 maxWithdraw,\n uint256 depositPrice,\n uint256 redeemPrice,\n uint128 pendingDepositRequest,\n uint128 pendingRedeemRequest,\n uint128 claimableCancelDepositRequest,\n uint128 claimableCancelRedeemRequest,\n bool pendingCancelDepositRequest,\n bool pendingCancelRedeemRequest\n );\n}\n" + }, + "src/vaults/interfaces/investments/IBaseRequestManager.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\nimport {AssetId} from \"src/common/types/AssetId.sol\";\n\nimport {IPoolManager} from \"src/vaults/interfaces/IPoolManager.sol\";\nimport {IBaseVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\nimport {IPoolEscrow, IEscrow} from \"src/vaults/interfaces/IEscrow.sol\";\n\ninterface IBaseRequestManager {\n // --- Events ---\n event File(bytes32 indexed what, address data);\n\n error FileUnrecognizedParam();\n error SenderNotVault();\n error AssetNotAllowed();\n error ExceedsMaxDeposit();\n error AssetMismatch();\n error VaultAlreadyExists();\n error VaultDoesNotExist();\n\n /// @notice Updates contract parameters of type address.\n /// @param what The bytes32 representation of 'gateway' or 'poolManager'.\n /// @param data The new contract address.\n function file(bytes32 what, address data) external;\n\n /// @notice Converts the assets value to share decimals.\n function convertToShares(IBaseVault vault, uint256 _assets) external view returns (uint256 shares);\n\n /// @notice Converts the shares value to assets decimals.\n function convertToAssets(IBaseVault vault, uint256 _shares) external view returns (uint256 assets);\n\n /// @notice Returns the timestamp of the last share price update for a vaultAddr.\n function priceLastUpdated(IBaseVault vault) external view returns (uint64 lastUpdated);\n\n /// @notice Returns the PoolManager contract address.\n function poolManager() external view returns (IPoolManager poolManager);\n\n /// @notice The global escrow used for funds that are not yet free to be used for a specific pool\n function globalEscrow() external view returns (IEscrow escrow);\n\n /// @notice Escrow per pool. Funds are associated to a specific pool\n function poolEscrow(PoolId poolId) external view returns (IPoolEscrow);\n\n /// @notice Adds new vault for `poolId`, `scId` and `asset`.\n function addVault(PoolId poolId, ShareClassId scId, IBaseVault vault, address asset, AssetId assetId) external;\n\n /// @notice Removes `vault` from `who`'s authorized callers\n function removeVault(PoolId poolId, ShareClassId scId, IBaseVault vault, address asset, AssetId assetId) external;\n\n /// @notice Returns the address of the vault for a given pool, share class and asset\n function vaultByAssetId(PoolId poolId, ShareClassId scId, AssetId assetId)\n external\n view\n returns (IBaseVault vault);\n}\n" + }, + "src/vaults/interfaces/investments/IDepositManager.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IBaseRequestManager} from \"src/vaults/interfaces/investments/IBaseRequestManager.sol\";\nimport {IBaseVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\n\ninterface IDepositManager is IBaseRequestManager {\n /// @notice Processes owner's asset deposit after the epoch has been executed on the corresponding CP instance and\n /// the deposit order\n /// has been successfully processed (partial fulfillment possible).\n /// Shares are transferred from the escrow to the receiver. Amount of shares is computed based of the amount\n /// of assets and the owner's share price.\n /// @dev The assets required to fulfill the deposit are already locked in escrow upon calling requestDeposit.\n /// The shares required to fulfill the deposit have already been minted and transferred to the escrow on\n /// fulfillDepositRequest.\n /// Receiver has to pass all the share token restrictions in order to receive the shares.\n function deposit(IBaseVault vault, uint256 assets, address receiver, address owner)\n external\n returns (uint256 shares);\n\n /// @notice Processes owner's share mint after the epoch has been executed on the corresponding CP instance and the\n /// deposit order has\n /// been successfully processed (partial fulfillment possible).\n /// Shares are transferred from the escrow to the receiver. Amount of assets is computed based of the amount\n /// of shares and the owner's share price.\n /// @dev The assets required to fulfill the mint are already locked in escrow upon calling requestDeposit.\n /// The shares required to fulfill the mint have already been minted and transferred to the escrow on\n /// fulfillDepositRequest.\n /// Receiver has to pass all the share token restrictions in order to receive the shares.\n function mint(IBaseVault vault, uint256 shares, address receiver, address owner)\n external\n returns (uint256 assets);\n\n /// @notice Returns the max amount of assets based on the unclaimed amount of shares after at least one successful\n /// deposit order fulfillment on the corresponding CP instance.\n function maxDeposit(IBaseVault vault, address user) external view returns (uint256);\n\n /// @notice Returns the max amount of shares a user can claim after at least one successful deposit order\n /// fulfillment on the corresponding CP instance.\n function maxMint(IBaseVault vault, address user) external view returns (uint256 shares);\n}\n" + }, + "src/vaults/interfaces/investments/IRedeemManager.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IBaseRequestManager} from \"src/vaults/interfaces/investments/IBaseRequestManager.sol\";\nimport {IBaseVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\n\ninterface IRedeemManager is IBaseRequestManager {\n event TriggerRedeemRequest(\n uint64 indexed poolId,\n bytes16 indexed scId,\n address user,\n address indexed asset,\n uint256 tokenId,\n uint128 shares\n );\n\n /// @notice Processes owner's share redemption after the epoch has been executed on the corresponding CP instance\n /// and the redeem order\n /// has been successfully processed (partial fulfillment possible).\n /// Assets are transferred from the escrow to the receiver. Amount of assets is computed based of the amount\n /// of shares and the owner's share price.\n /// @dev The shares required to fulfill the redemption were already locked in escrow on requestRedeem and burned\n /// on fulfillRedeemRequest.\n /// The assets required to fulfill the redemption have already been reserved in escrow on\n /// fulfillRedeemtRequest.\n function redeem(IBaseVault vault, uint256 shares, address receiver, address owner)\n external\n returns (uint256 assets);\n\n /// @notice Processes owner's asset withdrawal after the epoch has been executed on the corresponding CP instance\n /// and the redeem order\n /// has been successfully processed (partial fulfillment possible).\n /// Assets are transferred from the escrow to the receiver. Amount of shares is computed based of the amount\n /// of shares and the owner's share price.\n /// @dev The shares required to fulfill the withdrawal were already locked in escrow on requestRedeem and burned\n /// on fulfillRedeemRequest.\n /// The assets required to fulfill the withdrawal have already been reserved in escrow on\n /// fulfillRedeemtRequest.\n function withdraw(IBaseVault vault, uint256 assets, address receiver, address owner)\n external\n returns (uint256 shares);\n\n /// @notice Returns the max amount of shares based on the unclaimed number of assets after at least one successful\n /// redeem order fulfillment on the corresponding CP instance.\n function maxRedeem(IBaseVault vault, address user) external view returns (uint256 shares);\n\n /// @notice Returns the max amount of assets a user can claim after at least one successful redeem order fulfillment\n /// on the corresponding CP instance.\n function maxWithdraw(IBaseVault vault, address user) external view returns (uint256 assets);\n}\n" + }, + "src/vaults/interfaces/investments/ISyncDepositManager.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IDepositManager} from \"src/vaults/interfaces/investments/IDepositManager.sol\";\nimport {IBaseVault} from \"src/vaults/interfaces/IBaseVaults.sol\";\n\ninterface ISyncDepositManager is IDepositManager {\n function previewDeposit(IBaseVault vault, address sender, uint256 assets) external view returns (uint256);\n function previewMint(IBaseVault vault, address sender, uint256 shares) external view returns (uint256);\n}\n" + }, + "src/vaults/interfaces/investments/ISyncRequestManager.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {D18} from \"src/misc/types/D18.sol\";\n\nimport {AssetId} from \"src/common/types/AssetId.sol\";\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nimport {IUpdateContract} from \"src/vaults/interfaces/IUpdateContract.sol\";\nimport {ISyncDepositManager} from \"src/vaults/interfaces/investments/ISyncDepositManager.sol\";\n\n/// @dev Solely used locally as protection against stack-too-deep\nstruct Prices {\n /// @dev Price of 1 asset unit per share unit\n D18 assetPerShare;\n /// @dev Price of 1 pool unit per asset unit\n D18 poolPerAsset;\n /// @dev Price of 1 pool unit per share unit\n D18 poolPerShare;\n}\n\ninterface ISyncDepositValuation {\n /// @notice Returns the pool price per share for a given pool and share class, asset, and asset id.\n // The provided price is defined as POOL_UNIT/SHARE_UNIT.\n ///\n /// @param poolId The pool id\n /// @param scId The share class id\n /// @return price The pool price per share\n function pricePoolPerShare(PoolId poolId, ShareClassId scId) external view returns (D18 price);\n}\n\ninterface ISyncRequestManager is ISyncDepositManager, ISyncDepositValuation, IUpdateContract {\n event SetValuation(PoolId indexed poolId, ShareClassId indexed scId, address valuation);\n event SetMaxReserve(\n PoolId indexed poolId, ShareClassId indexed scId, address asset, uint256 tokenId, uint128 maxReserve\n );\n\n error ExceedsMaxMint();\n error ShareTokenDoesNotExist();\n error SecondaryManagerDoesNotExist();\n\n /// @notice Sets the valuation for a specific pool and share class.\n ///\n /// @param poolId The id of the pool\n /// @param scId The id of the share class\n /// @param valuation The address of the valuation contract\n function setValuation(PoolId poolId, ShareClassId scId, address valuation) external;\n\n /// @notice Sets the max reserve for a specific pool, share class and asset.\n ///\n /// @param poolId The id of the pool\n /// @param scId The id of the share class\n /// @param asset The address of the asset\n /// @param tokenId The asset token id, i.e. 0 for ERC20, or the token id for ERC6909\n /// @param maxReserve The amount of maximum reserve\n function setMaxReserve(PoolId poolId, ShareClassId scId, address asset, uint256 tokenId, uint128 maxReserve)\n external;\n\n /// @notice Returns the all three prices for a given pool, share class, asset, and asset id.\n ///\n /// @param poolId The pool id\n /// @param scId The share class id\n /// @param assetId The asset id corresponding to the asset and tokenId\n /// @return priceData The asset price per share, pool price per asset, and pool price per share\n function prices(PoolId poolId, ShareClassId scId, AssetId assetId)\n external\n view\n returns (Prices memory priceData);\n}\n" + }, + "src/vaults/interfaces/token/IShareToken.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {IERC20Metadata} from \"src/misc/interfaces/IERC20.sol\";\nimport {IERC7575Share} from \"src/misc/interfaces/IERC7575.sol\";\n\ninterface IERC1404 {\n /// @notice Detects if a transfer will be reverted and if so returns an appropriate reference code\n /// @param from Sending address\n /// @param to Receiving address\n /// @param value Amount of tokens being transferred\n /// @return Code by which to reference message for rejection reasoning\n /// @dev Overwrite with your custom transfer restriction logic\n function detectTransferRestriction(address from, address to, uint256 value) external view returns (uint8);\n\n /// @notice Returns a human-readable message for a given restriction code\n /// @param restrictionCode Identifier for looking up a message\n /// @return Text showing the restriction's reasoning\n /// @dev Overwrite with your custom message and restrictionCode handling\n function messageForTransferRestriction(uint8 restrictionCode) external view returns (string memory);\n}\n\ninterface IShareToken is IERC20Metadata, IERC7575Share, IERC1404 {\n // --- Events ---\n event File(bytes32 indexed what, address data);\n event SetHookData(address indexed user, bytes16 data);\n\n // --- Errors ---\n error NotAuthorizedOrHook();\n error ExceedsMaxSupply();\n error RestrictionsFailed();\n\n struct Balance {\n /// @dev The user balance is limited to uint128. This is safe because the decimals are limited to 18,\n /// thus the max balance is 2^128-1 / 10**18 = 3.40 * 10**20. This is also enforced on mint.\n uint128 amount;\n /// @dev There are 16 bytes that are used to store hook data (e.g. restrictions for users).\n bytes16 hookData;\n }\n\n // --- Administration ---\n /// @notice returns the hook that transfers perform callbacks to\n /// @dev MUST comply to `IHook` interface\n function hook() external view returns (address);\n\n /// @notice Updates a contract parameter\n /// @param what Accepts a bytes32 representation of 'name', 'symbol'\n function file(bytes32 what, string memory data) external;\n\n /// @notice Updates a contract parameter\n /// @param what Accepts a bytes32 representation of 'hook'\n function file(bytes32 what, address data) external;\n\n /// @notice updates the vault for a given `asset`\n function updateVault(address asset, address vault_) external;\n\n // --- ERC20 overrides ---\n /// @notice returns the 16 byte hook data of the given `user`.\n /// @dev Stored in the 128 most significant bits of the user balance\n function hookDataOf(address user) external view returns (bytes16);\n\n /// @notice update the 16 byte hook data of the given `user`\n function setHookData(address user, bytes16 hookData) external;\n\n /// @notice Function to mint tokens\n function mint(address user, uint256 value) external;\n\n /// @notice Function to burn tokens\n function burn(address user, uint256 value) external;\n\n /// @notice Checks if the tokens can be transferred given the input values\n function checkTransferRestriction(address from, address to, uint256 value) external view returns (bool);\n\n /// @notice Performs an authorized transfer, with `sender` as the given sender.\n /// @dev Requires allowance if `sender` != `from`\n function authTransferFrom(address sender, address from, address to, uint256 amount) external returns (bool);\n}\n" + }, + "src/vaults/legacy/LegacyVaultAdapter.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {PoolId} from \"src/common/types/PoolId.sol\";\nimport {ShareClassId} from \"src/common/types/ShareClassId.sol\";\n\nimport {ILegacyVault} from \"src/vaults/legacy/interfaces/ILegacyVault.sol\";\nimport {IInvestmentManager} from \"src/vaults/legacy/interfaces/IInvestmentManager.sol\";\nimport {ILegacyVaultAdapter} from \"src/vaults/legacy/interfaces/ILegacyVaultAdapter.sol\";\nimport {IShareToken} from \"src/vaults/interfaces/token/IShareToken.sol\";\nimport {AsyncVault} from \"src/vaults/AsyncVault.sol\";\nimport {IAsyncRequestManager} from \"src/vaults/interfaces/investments/IAsyncRequestManager.sol\";\nimport {BaseAsyncRedeemVault, IAsyncRedeemVault} from \"src/vaults/BaseVaults.sol\";\n\n/// @title LegacyVaultAdapter\n/// @notice An adapter connecting legacy ERC-7540 vaults from Centrifuge V2 to Centrifuge V3.\n///\n/// @dev This adapter acts as an `IInvestmentManager` for a single legacy `ILegacyVault` vault from Centrifuge V2.\n/// At the same time it acts like a new `IAsyncVault` for the `IAsyncRequestManager` manager of Centrifuge V3.\n/// The adapter needs to be deployed per legacy vault and allows a seamless interaction between Centrifuge V2\n/// vaults and Centrifuge V3 infrastructure. Thereby, allowing to migrate existing vaults to the new system.\ncontract LegacyVaultAdapter is AsyncVault, ILegacyVaultAdapter, IInvestmentManager {\n uint64 public immutable legacyPoolId;\n bytes16 public immutable legacyTrancheId;\n ILegacyVault public immutable legacyVault;\n\n constructor(\n ILegacyVault legacyVault_,\n PoolId poolId,\n uint64 legacyPoolId_,\n ShareClassId scId,\n bytes16 legacyTrancheId_,\n address asset,\n IShareToken token,\n address root,\n IAsyncRequestManager manager\n ) AsyncVault(poolId, scId, asset, token, root, manager) {\n require(legacyVault_.poolId() == legacyPoolId_, NotLegacyPoolId(legacyPoolId_, legacyVault_.poolId()));\n require(\n legacyVault_.trancheId() == legacyTrancheId_, NotLegacyTrancheId(legacyTrancheId_, legacyVault_.trancheId())\n );\n require(legacyVault_.asset() == asset, NotLegacyAsset(asset, legacyVault_.asset()));\n require(legacyVault_.share() == address(token), NotLegacyShare(address(token), legacyVault_.share()));\n\n legacyPoolId = legacyPoolId_;\n legacyTrancheId = legacyTrancheId_;\n legacyVault = legacyVault_;\n }\n\n /// @dev Check if the msg.sender is the legacy vault\n modifier legacy() {\n require(msg.sender == address(legacyVault), NotLegacyVault(msg.sender, address(legacyVault)));\n _;\n }\n\n //----------------------------------------------------------------------------------------------\n // IInvestmentManager handlers\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IInvestmentManager\n function requestDeposit(address, /* vault */ uint256 assets, address receiver, address owner, address source)\n public\n legacy\n returns (bool)\n {\n return asyncManager().requestDeposit(this, assets, receiver, owner, source);\n }\n\n /// @inheritdoc IInvestmentManager\n function requestRedeem(address, /* vault */ uint256 shares, address receiver, address owner, address source)\n public\n legacy\n returns (bool)\n {\n return asyncManager().requestRedeem(this, shares, receiver, owner, source);\n }\n\n /// @inheritdoc IInvestmentManager\n function cancelDepositRequest(address, /* vault */ address owner, address source) public legacy {\n return asyncManager().cancelDepositRequest(this, owner, source);\n }\n\n /// @inheritdoc IInvestmentManager\n function cancelRedeemRequest(address, /* vault */ address owner, address source) public legacy {\n return asyncManager().cancelRedeemRequest(this, owner, source);\n }\n\n //----------------------------------------------------------------------------------------------\n // IInvestmentManager view methods\n //----------------------------------------------------------------------------------------------\n\n function escrow() public view returns (address) {\n return address(manager.globalEscrow());\n }\n\n /// @inheritdoc IInvestmentManager\n function convertToShares(address, /* vault */ uint256 _assets) public view returns (uint256 shares) {\n shares = asyncManager().convertToShares(this, _assets);\n }\n\n /// @inheritdoc IInvestmentManager\n function convertToAssets(address, /* vault */ uint256 _shares) public view returns (uint256 assets) {\n assets = asyncManager().convertToAssets(this, _shares);\n }\n\n /// @inheritdoc IInvestmentManager\n function maxDeposit(address, /* vault */ address user) public view returns (uint256 assets) {\n assets = asyncManager().maxDeposit(this, user);\n }\n\n /// @inheritdoc IInvestmentManager\n function maxMint(address, /* vault */ address user) public view returns (uint256 shares) {\n shares = asyncManager().maxMint(this, user);\n }\n\n /// @inheritdoc IInvestmentManager\n function maxWithdraw(address, /* vault */ address user) public view returns (uint256 assets) {\n assets = asyncManager().maxWithdraw(this, user);\n }\n\n /// @inheritdoc IInvestmentManager\n function maxRedeem(address, /* vault */ address user) public view returns (uint256 shares) {\n shares = asyncManager().maxRedeem(this, user);\n }\n\n /// @inheritdoc IInvestmentManager\n function pendingDepositRequest(address, /* vault */ address user) public view returns (uint256 assets) {\n assets = asyncManager().pendingDepositRequest(this, user);\n }\n\n /// @inheritdoc IInvestmentManager\n function pendingRedeemRequest(address, /* vault */ address user) public view returns (uint256 shares) {\n shares = asyncManager().pendingRedeemRequest(this, user);\n }\n\n /// @inheritdoc IInvestmentManager\n function pendingCancelDepositRequest(address, /* vault */ address user) public view returns (bool isPending) {\n isPending = asyncManager().pendingCancelDepositRequest(this, user);\n }\n\n /// @inheritdoc IInvestmentManager\n function pendingCancelRedeemRequest(address, /* vault */ address user) public view returns (bool isPending) {\n isPending = asyncManager().pendingCancelRedeemRequest(this, user);\n }\n\n /// @inheritdoc IInvestmentManager\n function claimableCancelDepositRequest(address, /* vault */ address user) public view returns (uint256 assets) {\n assets = asyncManager().claimableCancelDepositRequest(this, user);\n }\n\n /// @inheritdoc IInvestmentManager\n function claimableCancelRedeemRequest(address, /* vault */ address user) public view returns (uint256 shares) {\n shares = asyncManager().claimableCancelRedeemRequest(this, user);\n }\n\n /// @inheritdoc IInvestmentManager\n function priceLastUpdated(address /* vault */ ) public view returns (uint64 lastUpdated) {\n lastUpdated = manager.priceLastUpdated(this);\n }\n\n //----------------------------------------------------------------------------------------------\n // IInvestmentManager vault claim methods\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IInvestmentManager\n function deposit(address, /* vault */ uint256 assets, address receiver, address owner)\n public\n legacy\n returns (uint256 shares)\n {\n shares = asyncManager().deposit(this, assets, receiver, owner);\n }\n\n /// @inheritdoc IInvestmentManager\n function mint(address, /* vault */ uint256 shares, address receiver, address owner)\n public\n legacy\n returns (uint256 assets)\n {\n assets = asyncManager().mint(this, shares, receiver, owner);\n }\n\n /// @inheritdoc IInvestmentManager\n function redeem(address, /* vault */ uint256 shares, address receiver, address owner)\n public\n legacy\n returns (uint256 assets)\n {\n assets = asyncManager().redeem(this, shares, receiver, owner);\n }\n\n /// @inheritdoc IInvestmentManager\n function withdraw(address, /* vault */ uint256 assets, address receiver, address owner)\n public\n legacy\n returns (uint256 shares)\n {\n shares = asyncManager().withdraw(this, assets, receiver, owner);\n }\n\n /// @inheritdoc IInvestmentManager\n function claimCancelDepositRequest(address, /* vault */ address receiver, address owner)\n public\n legacy\n returns (uint256 assets)\n {\n assets = asyncManager().claimCancelDepositRequest(this, receiver, owner);\n }\n\n /// @inheritdoc IInvestmentManager\n function claimCancelRedeemRequest(address, /* vault */ address receiver, address owner)\n public\n legacy\n returns (uint256 shares)\n {\n shares = asyncManager().claimCancelRedeemRequest(this, receiver, owner);\n }\n\n //----------------------------------------------------------------------------------------------\n // Event emitters\n //----------------------------------------------------------------------------------------------\n\n function onDepositClaimable(address controller, uint256 assets, uint256 shares) public override auth {\n legacyVault.onDepositClaimable(controller, assets, shares);\n }\n\n function onCancelDepositClaimable(address controller, uint256 assets) public override auth {\n legacyVault.onCancelDepositClaimable(controller, assets);\n }\n\n function onRedeemRequest(address controller, address owner, uint256 shares)\n public\n override(BaseAsyncRedeemVault, IAsyncRedeemVault)\n auth\n {\n legacyVault.onRedeemRequest(controller, owner, shares);\n }\n\n function onRedeemClaimable(address controller, uint256 assets, uint256 shares)\n public\n override(BaseAsyncRedeemVault, IAsyncRedeemVault)\n auth\n {\n legacyVault.onRedeemClaimable(controller, assets, shares);\n }\n\n function onCancelRedeemClaimable(address controller, uint256 shares)\n public\n override(BaseAsyncRedeemVault, IAsyncRedeemVault)\n auth\n {\n legacyVault.onCancelRedeemClaimable(controller, shares);\n }\n}\n" + }, + "src/vaults/legacy/interfaces/IInvestmentManager.sol": { + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.5.0;\n\n/// @notice A stripped down version of the Centrifuge V2 investment manager.\n///\n/// @dev This interface is needed to ensure adapters for legacy vaults are provided with the expected interface.\ninterface IInvestmentManager {\n /// @notice Documentation see Centrifuge V2 repository.\n function escrow() external view returns (address);\n\n // --- Outgoing message handling ---\n /// @notice Documentation see Centrifuge V2 repository.\n function requestDeposit(address vault, uint256 assets, address receiver, address owner, address source)\n external\n returns (bool);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function requestRedeem(address vault, uint256 shares, address receiver, address, /* owner */ address source)\n external\n returns (bool);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function cancelDepositRequest(address vault, address owner, address source) external;\n\n /// @notice Documentation see Centrifuge V2 repository.\n function cancelRedeemRequest(address vault, address owner, address source) external;\n\n // --- View functions ---\n /// @notice Documentation see Centrifuge V2 repository.\n function convertToShares(address vault, uint256 _assets) external view returns (uint256 shares);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function convertToAssets(address vault, uint256 _shares) external view returns (uint256 assets);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function maxDeposit(address vault, address user) external view returns (uint256);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function maxMint(address vault, address user) external view returns (uint256 shares);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function maxWithdraw(address vault, address user) external view returns (uint256 assets);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function maxRedeem(address vault, address user) external view returns (uint256 shares);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function pendingDepositRequest(address vault, address user) external view returns (uint256 assets);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function pendingRedeemRequest(address vault, address user) external view returns (uint256 shares);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function pendingCancelDepositRequest(address vault, address user) external view returns (bool isPending);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function pendingCancelRedeemRequest(address vault, address user) external view returns (bool isPending);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function claimableCancelDepositRequest(address vault, address user) external view returns (uint256 assets);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function claimableCancelRedeemRequest(address vault, address user) external view returns (uint256 shares);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function priceLastUpdated(address vault) external view returns (uint64 lastUpdated);\n\n // --- Vault claim functions ---\n /// @notice Documentation see Centrifuge V2 repository.\n function deposit(address vault, uint256 assets, address receiver, address owner)\n external\n returns (uint256 shares);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function mint(address vault, uint256 shares, address receiver, address owner) external returns (uint256 assets);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function redeem(address vault, uint256 shares, address receiver, address owner) external returns (uint256 assets);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function withdraw(address vault, uint256 assets, address receiver, address owner)\n external\n returns (uint256 shares);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function claimCancelDepositRequest(address vault, address receiver, address owner)\n external\n returns (uint256 assets);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function claimCancelRedeemRequest(address vault, address receiver, address owner)\n external\n returns (uint256 shares);\n}\n" + }, + "src/vaults/legacy/interfaces/ILegacyVault.sol": { + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.5.0;\n\n/// @notice A stripped down version of the Centrifuge V2 ERC-7540 vault.\n///\n/// @dev This interface is needed to ensure adapters for legacy vaults are provided with the expected interface.\ninterface ILegacyVault {\n /// @notice Documentation see Centrifuge V2 repository.\n function poolId() external view returns (uint64);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function trancheId() external view returns (bytes16);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function asset() external view returns (address);\n\n /// @notice Documentation see Centrifuge V2 repository.\n function share() external view returns (address);\n\n /// @notice Callback when a redeem Request is triggered externally;\n function onRedeemRequest(address controller, address owner, uint256 shares) external;\n\n /// @notice Callback when a deposit Request becomes claimable\n function onDepositClaimable(address owner, uint256 assets, uint256 shares) external;\n\n /// @notice Callback when a redeem Request becomes claimable\n function onRedeemClaimable(address owner, uint256 assets, uint256 shares) external;\n\n /// @notice Callback when a claim deposit Request becomes claimable\n function onCancelDepositClaimable(address owner, uint256 assets) external;\n\n /// @notice Callback when a claim redeem Request becomes claimable\n function onCancelRedeemClaimable(address owner, uint256 shares) external;\n}\n" + }, + "src/vaults/legacy/interfaces/ILegacyVaultAdapter.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.5.0;\n\ninterface ILegacyVaultAdapter {\n error NotLegacyVault(address sender, address legacyVault);\n error NotLegacyPoolId(uint64 providedPoolId, uint64 legacyPoolId);\n error NotLegacyTrancheId(bytes16 providedTrancheId, bytes16 legacyTrancheId);\n error NotLegacyAsset(address providedAsset, address legacyAsset);\n error NotLegacyShare(address providedShare, address legacyShare);\n}\n" + }, + "src/vaults/token/ShareToken.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.28;\n\nimport {ERC20} from \"src/misc/ERC20.sol\";\nimport {IERC20, IERC20Metadata} from \"src/misc/interfaces/IERC20.sol\";\nimport {MathLib} from \"src/misc/libraries/MathLib.sol\";\nimport {IERC7575Share, IERC165} from \"src/misc/interfaces/IERC7575.sol\";\n\nimport {\n IHook,\n HookData,\n SUCCESS_CODE_ID,\n SUCCESS_MESSAGE,\n ERROR_CODE_ID,\n ERROR_MESSAGE\n} from \"src/common/interfaces/IHook.sol\";\nimport {IShareToken, IERC1404} from \"src/vaults/interfaces/token/IShareToken.sol\";\n\n/// @title Share Token\n/// @notice Extension of ERC20 + ERC1404,\n/// integrating an external hook optionally for ERC20 callbacks and ERC1404 checks.\ncontract ShareToken is ERC20, IShareToken {\n using MathLib for uint256;\n\n mapping(address => Balance) private balances;\n\n /// @inheritdoc IShareToken\n address public hook;\n\n /// @inheritdoc IERC7575Share\n mapping(address asset => address) public vault;\n\n constructor(uint8 decimals_) ERC20(decimals_) {}\n\n modifier authOrHook() {\n require(wards[msg.sender] == 1 || msg.sender == hook, NotAuthorizedOrHook());\n _;\n }\n\n //----------------------------------------------------------------------------------------------\n // Administration\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IShareToken\n function file(bytes32 what, address data) external authOrHook {\n if (what == \"hook\") hook = data;\n else revert FileUnrecognizedParam();\n emit File(what, data);\n }\n\n /// @inheritdoc IShareToken\n function file(bytes32 what, string memory data) public override(ERC20, IShareToken) auth {\n super.file(what, data);\n }\n\n /// @inheritdoc IShareToken\n function updateVault(address asset, address vault_) external auth {\n vault[asset] = vault_;\n emit VaultUpdate(asset, vault_);\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-20 overrides\n //----------------------------------------------------------------------------------------------\n\n function _balanceOf(address user) internal view override returns (uint256) {\n return balances[user].amount;\n }\n\n function _setBalance(address user, uint256 value) internal override {\n balances[user].amount = value.toUint128();\n }\n\n /// @inheritdoc IShareToken\n function hookDataOf(address user) public view returns (bytes16) {\n return balances[user].hookData;\n }\n\n /// @inheritdoc IShareToken\n function setHookData(address user, bytes16 hookData) public authOrHook {\n balances[user].hookData = hookData;\n emit SetHookData(user, hookData);\n }\n\n /// @inheritdoc IERC20\n function transfer(address to, uint256 value) public override(ERC20, IERC20) returns (bool success) {\n success = super.transfer(to, value);\n _onTransfer(msg.sender, to, value);\n }\n\n /// @inheritdoc IERC20\n function transferFrom(address from, address to, uint256 value)\n public\n override(ERC20, IERC20)\n returns (bool success)\n {\n success = super.transferFrom(from, to, value);\n _onTransfer(from, to, value);\n }\n\n /// @inheritdoc IShareToken\n function mint(address to, uint256 value) public override(ERC20, IShareToken) {\n super.mint(to, value);\n require(totalSupply <= type(uint128).max, ExceedsMaxSupply());\n _onTransfer(address(0), to, value);\n }\n\n /// @inheritdoc IShareToken\n function burn(address from, uint256 value) public override(ERC20, IShareToken) {\n super.burn(from, value);\n _onTransfer(from, address(0), value);\n }\n\n function _onTransfer(address from, address to, uint256 value) internal {\n address hook_ = hook;\n require(\n hook_ == address(0)\n || IHook(hook_).onERC20Transfer(from, to, value, HookData(hookDataOf(from), hookDataOf(to)))\n == IHook.onERC20Transfer.selector,\n RestrictionsFailed()\n );\n }\n\n /// @inheritdoc IShareToken\n function authTransferFrom(address sender, address from, address to, uint256 value)\n public\n auth\n returns (bool success)\n {\n success = _transferFrom(sender, from, to, value);\n address hook_ = hook;\n if (hook_ != address(0)) {\n IHook(hook_).onERC20AuthTransfer(sender, from, to, value, HookData(hookDataOf(from), hookDataOf(to)));\n }\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-1404\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IShareToken\n function checkTransferRestriction(address from, address to, uint256 value) public view returns (bool) {\n return detectTransferRestriction(from, to, value) == SUCCESS_CODE_ID;\n }\n\n /// @inheritdoc IERC1404\n function detectTransferRestriction(address from, address to, uint256 value) public view returns (uint8) {\n address hook_ = hook;\n if (hook_ == address(0)) return SUCCESS_CODE_ID;\n return IHook(hook_).checkERC20Transfer(from, to, value, HookData(hookDataOf(from), hookDataOf(to)))\n ? SUCCESS_CODE_ID\n : ERROR_CODE_ID;\n }\n\n /// @inheritdoc IERC1404\n function messageForTransferRestriction(uint8 restrictionCode) external pure returns (string memory) {\n return restrictionCode == SUCCESS_CODE_ID ? SUCCESS_MESSAGE : ERROR_MESSAGE;\n }\n\n //----------------------------------------------------------------------------------------------\n // ERC-165\n //----------------------------------------------------------------------------------------------\n\n /// @inheritdoc IERC165\n function supportsInterface(bytes4 interfaceId) external pure override returns (bool) {\n return interfaceId == type(IERC7575Share).interfaceId || interfaceId == type(IERC165).interfaceId;\n }\n}\n" + } + }, + "settings": { + "remappings": [ + "forge-std/=lib/forge-std/src/", + "@chimera/=lib/chimera/src/", + "chimera/=lib/chimera/src/", + "ds-test/=lib/chimera/lib/forge-std/lib/ds-test/src/" + ], + "optimizer": { "enabled": true, "runs": 1 }, + "metadata": { + "useLiteralContent": false, + "bytecodeHash": "none", + "appendCBOR": true + }, + "outputSelection": { + "lib/forge-std/src/interfaces/IERC165.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/common/GasService.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/common/Gateway.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/common/Guardian.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/common/MessageDispatcher.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/common/MessageProcessor.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/common/Root.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/common/TokenRecoverer.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/common/adapters/AxelarAdapter.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/common/adapters/WormholeAdapter.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/common/interfaces/IAdapter.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/common/interfaces/IAxelarAdapter.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/common/interfaces/IGasService.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/common/interfaces/IGateway.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/common/interfaces/IGatewayHandlers.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/common/interfaces/IGatewaySenders.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/common/interfaces/IGuardian.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/common/interfaces/IGuardianActions.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/common/interfaces/IHook.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/common/interfaces/IMessageDispatcher.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/common/interfaces/IMessageHandler.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/common/interfaces/IMessageProcessor.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/common/interfaces/IMessageProperties.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/common/interfaces/IMessageSender.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/common/interfaces/IRoot.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/common/interfaces/ITokenRecoverer.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/common/interfaces/IWormholeAdapter.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/common/libraries/MessageLib.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/common/libraries/MessageProofLib.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/common/libraries/PricingLib.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/common/types/AccountId.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/common/types/AssetId.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/common/types/PoolId.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/common/types/ShareClassId.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/hooks/FreezeOnly.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/hooks/FullRestrictions.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/hooks/RedemptionRestrictions.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/hooks/interfaces/IFreezable.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/hooks/interfaces/IMemberlist.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/hub/Accounting.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/hub/Holdings.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/hub/Hub.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/hub/HubRegistry.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/hub/ShareClassManager.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/hub/interfaces/IAccounting.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/hub/interfaces/IHoldings.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/hub/interfaces/IHub.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/hub/interfaces/IHubRegistry.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/hub/interfaces/IShareClassManager.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/misc/Auth.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/misc/BaseValuation.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/misc/ERC20.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/misc/IdentityValuation.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/misc/Multicall.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/misc/Recoverable.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/misc/ReentrancyProtection.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/misc/interfaces/IAuth.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/misc/interfaces/IBaseValuation.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/misc/interfaces/IERC20.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/misc/interfaces/IERC6909.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/misc/interfaces/IERC7540.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/misc/interfaces/IERC7575.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/misc/interfaces/IERC7726.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/misc/interfaces/IIdentityValuation.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/misc/interfaces/IMulticall.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/misc/interfaces/IRecoverable.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/misc/libraries/ArrayLib.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/misc/libraries/BitmapLib.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/misc/libraries/BytesLib.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/misc/libraries/CastLib.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/misc/libraries/EIP712Lib.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/misc/libraries/MathLib.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/misc/libraries/SafeTransferLib.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/misc/libraries/SignatureLib.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/misc/libraries/StringLib.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/misc/libraries/TransientArrayLib.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/misc/libraries/TransientBytesLib.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/misc/libraries/TransientStorageLib.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/misc/types/D18.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/vaults/AsyncRequestManager.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/vaults/AsyncVault.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/vaults/BalanceSheet.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/vaults/BaseRequestManager.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/vaults/BaseVaults.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/vaults/Escrow.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/vaults/PoolManager.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/vaults/SyncDepositVault.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/vaults/SyncRequestManager.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/vaults/VaultRouter.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/vaults/factories/AsyncVaultFactory.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/vaults/factories/PoolEscrowFactory.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/vaults/factories/SyncDepositVaultFactory.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/vaults/factories/TokenFactory.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/vaults/interfaces/IBalanceSheet.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/vaults/interfaces/IBaseVaults.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/vaults/interfaces/IEscrow.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/vaults/interfaces/IPoolManager.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/vaults/interfaces/IUpdateContract.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/vaults/interfaces/IVaultRouter.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/vaults/interfaces/factories/IPoolEscrowFactory.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/vaults/interfaces/factories/ITokenFactory.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/vaults/interfaces/factories/IVaultFactory.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/vaults/interfaces/investments/IAsyncDepositManager.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/vaults/interfaces/investments/IAsyncRedeemManager.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/vaults/interfaces/investments/IAsyncRequestManager.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/vaults/interfaces/investments/IBaseRequestManager.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/vaults/interfaces/investments/IDepositManager.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/vaults/interfaces/investments/IRedeemManager.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/vaults/interfaces/investments/ISyncDepositManager.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/vaults/interfaces/investments/ISyncRequestManager.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/vaults/interfaces/token/IShareToken.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/vaults/legacy/LegacyVaultAdapter.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/vaults/legacy/interfaces/IInvestmentManager.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/vaults/legacy/interfaces/ILegacyVault.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/vaults/legacy/interfaces/ILegacyVaultAdapter.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + }, + "src/vaults/token/ShareToken.sol": { + "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"] + } + }, + "evmVersion": "cancun", + "viaIR": true, + "libraries": {} + } +} diff --git a/crates/resolc/src/tests/data/standard_json/solidity_contracts.json b/crates/resolc/src/tests/data/standard_json/solidity_contracts.json index b50cd2f..8edc856 100644 --- a/crates/resolc/src/tests/data/standard_json/solidity_contracts.json +++ b/crates/resolc/src/tests/data/standard_json/solidity_contracts.json @@ -91,11 +91,19 @@ "viaIR": true, "outputSelection": { "*": { - "": [], - "*": ["evm.bytecode"] + "": ["ast"], + "*": [ + "abi", + "metadata", + "irOptimized", + "evm.methodIdentifiers", + "evm.bytecode", + "evm.deployedBytecode", + "evm.assembly" + ] } }, - "evmVersion": "berlin", + "evmVersion": "cancun", "remappings": ["forge-std/=lib/forge-std/src/"] } } diff --git a/crates/resolc/src/tests/data/standard_json/yul_no_pvm_codegen.json b/crates/resolc/src/tests/data/standard_json/yul_no_pvm_codegen.json new file mode 100644 index 0000000..6727573 --- /dev/null +++ b/crates/resolc/src/tests/data/standard_json/yul_no_pvm_codegen.json @@ -0,0 +1,23 @@ +{ + "language": "Yul", + "sources": { + "Test": { + "content": "object \"Return\" { code { { return(0, 0) } } object \"Return_deployed\" { code { { return(0, 0) } } } }" + } + }, + "settings": { + "optimizer": { + "enabled": false + }, + "metadata": { + "useLiteralContent": true + }, + "outputSelection": { + "*": { + "": [], + "*": [] + } + }, + "libraries": {} + } +} diff --git a/crates/resolc/src/tests/data/standard_json/yul_pvm_codegen.json b/crates/resolc/src/tests/data/standard_json/yul_pvm_codegen.json new file mode 100644 index 0000000..425a98c --- /dev/null +++ b/crates/resolc/src/tests/data/standard_json/yul_pvm_codegen.json @@ -0,0 +1,23 @@ +{ + "language": "Yul", + "sources": { + "Test": { + "content": "object \"Return\" { code { { return(0, 0) } } object \"Return_deployed\" { code { { return(0, 0) } } } }" + } + }, + "settings": { + "optimizer": { + "enabled": true + }, + "metadata": { + "useLiteralContent": true + }, + "outputSelection": { + "*": { + "": [], + "*": ["evm"] + } + }, + "libraries": {} + } +} diff --git a/crates/resolc/src/tests/unit/standard_json.rs b/crates/resolc/src/tests/unit/standard_json.rs index 15ac541..089a921 100644 --- a/crates/resolc/src/tests/unit/standard_json.rs +++ b/crates/resolc/src/tests/unit/standard_json.rs @@ -1,8 +1,13 @@ use std::path::PathBuf; -use revive_solc_json_interface::SolcStandardJsonInput; +use revive_solc_json_interface::{ + SolcStandardJsonInput, SolcStandardJsonInputSettingsSelectionFileFlag, +}; -use crate::test_utils::build_yul_standard_json; +use crate::{ + cli_utils::{STANDARD_JSON_PVM_CODEGEN_PER_FILE_PATH, STANDARD_JSON_YUL_PVM_CODEGEN_PATH}, + test_utils::build_yul_standard_json, +}; #[test] fn standard_json_yul_solc() { @@ -51,3 +56,111 @@ fn standard_json_yul_solc_urls() { .object .is_empty()) } + +#[test] +fn standard_json_selection_to_prune_with_evm_child_per_file() { + let solc_input = SolcStandardJsonInput::try_from(Some( + PathBuf::from(STANDARD_JSON_PVM_CODEGEN_PER_FILE_PATH).as_path(), + )) + .unwrap(); + let selection_to_prune = solc_input.settings.selection_to_prune(); + + // Verify that every flag exists in the selection to prune for the `all` wildcard. + for flag in SolcStandardJsonInputSettingsSelectionFileFlag::all() { + assert!( + selection_to_prune.all.contains(*flag), + "`{}` should be a selection to prune from the `all` wildcard settings", + serde_json::to_string(flag).unwrap(), + ); + } + + // The `abi`, `metadata`, `evm.methodIdentifiers`, `evm.bytecode` are requested + // per file, thus all other flags except `evm` should be in the selection to prune. + let expected_selection_to_prune_per_file = &[ + SolcStandardJsonInputSettingsSelectionFileFlag::Devdoc, + SolcStandardJsonInputSettingsSelectionFileFlag::Userdoc, + SolcStandardJsonInputSettingsSelectionFileFlag::StorageLayout, + SolcStandardJsonInputSettingsSelectionFileFlag::AST, + SolcStandardJsonInputSettingsSelectionFileFlag::Yul, + SolcStandardJsonInputSettingsSelectionFileFlag::EVMLA, + SolcStandardJsonInputSettingsSelectionFileFlag::EVMDBC, + SolcStandardJsonInputSettingsSelectionFileFlag::Assembly, + SolcStandardJsonInputSettingsSelectionFileFlag::Ir, + ]; + + for (file_name, selection_to_prune_per_file) in &selection_to_prune.files.files { + // Verify that every expected flag exists in the selection to prune for a specific file. + for flag in expected_selection_to_prune_per_file { + assert!( + selection_to_prune_per_file.contains(*flag), + "`{}` should be a selection to prune from file `{file_name}`", + serde_json::to_string(flag).unwrap() + ); + } + + // Verify that every unexpected flag is omitted from the selection to prune. + for flag in SolcStandardJsonInputSettingsSelectionFileFlag::all() { + if !expected_selection_to_prune_per_file.contains(flag) { + assert!( + !selection_to_prune_per_file.contains(*flag), + "`{}` should not be a selection to prune from file `{file_name}`", + serde_json::to_string(flag).unwrap() + ); + } + } + } +} + +#[test] +fn standard_json_selection_to_prune_with_evm_parent_for_all() { + let solc_input = SolcStandardJsonInput::try_from(Some( + PathBuf::from(STANDARD_JSON_YUL_PVM_CODEGEN_PATH).as_path(), + )) + .unwrap(); + let selection_to_prune = solc_input.settings.selection_to_prune(); + + // Only the `evm` parent is requested in the `all` wildcard, thus all flags + // except `evm` and its child flags should be in the selection to prune. + // (Exception: `evm.legacyAssembly` is the only `evm` child flag that should also be pruned). + let expected_selection_to_prune_for_all = &[ + SolcStandardJsonInputSettingsSelectionFileFlag::ABI, + SolcStandardJsonInputSettingsSelectionFileFlag::Metadata, + SolcStandardJsonInputSettingsSelectionFileFlag::Devdoc, + SolcStandardJsonInputSettingsSelectionFileFlag::Userdoc, + SolcStandardJsonInputSettingsSelectionFileFlag::StorageLayout, + SolcStandardJsonInputSettingsSelectionFileFlag::AST, + SolcStandardJsonInputSettingsSelectionFileFlag::Yul, + SolcStandardJsonInputSettingsSelectionFileFlag::EVMLA, + SolcStandardJsonInputSettingsSelectionFileFlag::Ir, + ]; + + // Verify that every expected flag exists in the selection to prune for the `all` wildcard. + for flag in expected_selection_to_prune_for_all { + assert!( + selection_to_prune.all.contains(*flag), + "`{}` should be a selection to prune from the `all` wildcard settings", + serde_json::to_string(flag).unwrap() + ); + } + + // Verify that every unexpected flag is omitted from the selection to prune for the `all` wildcard. + for flag in SolcStandardJsonInputSettingsSelectionFileFlag::all() { + if !expected_selection_to_prune_for_all.contains(flag) { + assert!( + !selection_to_prune.all.contains(*flag), + "`{}` should not be a selection to prune from the `all` wildcard settings", + serde_json::to_string(flag).unwrap(), + ); + } + } + + // Verify that there is nothing to be pruned for each file when there are no per-file requests. + assert!( + solc_input.settings.output_selection.files.is_empty(), + "no output should be requested per file" + ); + assert!( + selection_to_prune.files.is_empty(), + "no selections should be pruned per file when there are no per-file requests" + ); +} diff --git a/crates/solc-json-interface/src/standard_json/input/settings/selection/file/flag.rs b/crates/solc-json-interface/src/standard_json/input/settings/selection/file/flag.rs index 99faaf2..f213b20 100644 --- a/crates/solc-json-interface/src/standard_json/input/settings/selection/file/flag.rs +++ b/crates/solc-json-interface/src/standard_json/input/settings/selection/file/flag.rs @@ -49,12 +49,53 @@ pub enum Flag { } impl Flag { - /// Whether this selection flag is required for the revive codegen. + /// Returns all flags. + pub fn all() -> &'static [Self] { + &[ + Self::ABI, + Self::Metadata, + Self::Devdoc, + Self::Userdoc, + Self::MethodIdentifiers, + Self::StorageLayout, + Self::AST, + Self::Yul, + Self::EVM, + Self::EVMLA, + Self::EVMBC, + Self::EVMDBC, + Self::Assembly, + Self::Ir, + ] + } + + /// Returns the EVM child flags. + /// Excludes the EVM legacy assembly as it does not have a PVM equivalent. + pub fn evm_children() -> &'static [Self] { + &[ + Self::MethodIdentifiers, + Self::EVMBC, + Self::EVMDBC, + Self::Assembly, + ] + } + + /// Returns the flags required by our compilation process. + pub fn codegen_requirements() -> &'static [Self] { + &[ + Self::AST, + Self::MethodIdentifiers, + Self::Metadata, + Self::Yul, + ] + } + + /// Whether this selection flag is specific for the solc backend only. /// /// Specifically, EVM bytecode and related flags should never be requested. /// It will be replaced by PVM code anyways. - pub fn is_required_for_codegen(&self) -> bool { - !matches!( + pub fn is_evm_codegen(&self) -> bool { + matches!( self, Flag::EVMBC | Flag::EVMDBC | Flag::EVMLA | Flag::EVM | Flag::Assembly ) diff --git a/crates/solc-json-interface/src/standard_json/input/settings/selection/file/mod.rs b/crates/solc-json-interface/src/standard_json/input/settings/selection/file/mod.rs index ac35e30..224f3f9 100644 --- a/crates/solc-json-interface/src/standard_json/input/settings/selection/file/mod.rs +++ b/crates/solc-json-interface/src/standard_json/input/settings/selection/file/mod.rs @@ -15,13 +15,14 @@ pub struct File { /// The per-file output selections. #[serde(default, rename = "", skip_serializing_if = "HashSet::is_empty")] pub per_file: HashSet, - /// The per-contract output selections. + /// The per-contract output selections, common for all contracts. + /// Only the "all" (`*`) wildcard is available for robustness reasons. #[serde(default, rename = "*", skip_serializing_if = "HashSet::is_empty")] pub per_contract: HashSet, } impl File { - /// A shortcut constructor. + /// Creates the selection for all contracts with arbitrary `flags`. pub fn new(flags: Vec) -> Self { let mut per_file = HashSet::new(); let mut per_contract = HashSet::new(); @@ -41,6 +42,11 @@ impl File { } } + /// Creates the selection required by our compilation process. + pub fn new_required_for_codegen() -> Self { + Self::new(SelectionFlag::codegen_requirements().into()) + } + /// Creates the selection required for test compilation (includes EVM bytecode). pub fn new_required_for_tests() -> Self { Self { @@ -62,44 +68,66 @@ impl File { self } - /// Returns flags that are going to be automatically added by the compiler, - /// but were not explicitly requested by the user. + /// Returns flags that were not explicitly requested by the user. /// - /// Afterwards, the flags are used to prune JSON output before returning it. + /// These flags are used to prune JSON output before returning it, + /// removing any output that was automatically added but not requested. pub fn selection_to_prune(&self) -> Self { - let required_per_file = vec![SelectionFlag::AST]; - let required_per_contract = vec![ - SelectionFlag::MethodIdentifiers, - SelectionFlag::Metadata, - SelectionFlag::Yul, - ]; + let unset_per_file = SelectionFlag::all() + .iter() + .copied() + .filter(|flag| !self.per_file.contains(flag)) + .collect(); - let mut unset_per_file = HashSet::with_capacity(required_per_file.len()); - let mut unset_per_contract = HashSet::with_capacity(required_per_contract.len()); + let requests_evm_parent = self.contains(SelectionFlag::EVM); + let evm_children = SelectionFlag::evm_children(); + let requests_evm_child = self.contains_any(evm_children); + + let unset_per_contract: HashSet<_> = SelectionFlag::all() + .iter() + .copied() + .filter(|flag| { + // Never prune EVM children when the EVM parent is requested. + if requests_evm_parent && evm_children.contains(flag) { + return false; + } + // Never prune the EVM parent when any of its children are requested. + if requests_evm_child && *flag == SelectionFlag::EVM { + return false; + } + !self.per_contract.contains(flag) + }) + .collect(); - for flag in required_per_file { - if !self.per_file.contains(&flag) { - unset_per_file.insert(flag); - } - } - for flag in required_per_contract { - if !self.per_contract.contains(&flag) { - unset_per_contract.insert(flag); - } - } Self { per_file: unset_per_file, per_contract: unset_per_contract, } } - /// Whether the flag is requested. - pub fn contains(&self, flag: &SelectionFlag) -> bool { + + /// Checks whether the `flag` is requested. + pub fn contains(&self, flag: SelectionFlag) -> bool { match flag { - flag @ SelectionFlag::AST => self.per_file.contains(flag), - flag => self.per_contract.contains(flag), + SelectionFlag::AST => self.per_file.contains(&flag), + _ => self.per_contract.contains(&flag), } } + /// Checks whether any of the `flags` is requested. + pub fn contains_any(&self, flags: &[SelectionFlag]) -> bool { + flags.iter().any(|&flag| self.contains(flag)) + } + + /// Checks whether code generation is requested. + pub fn requests_codegen(&self) -> bool { + self.contains_any(&[ + SelectionFlag::EVM, + SelectionFlag::EVMBC, + SelectionFlag::EVMDBC, + SelectionFlag::Assembly, + ]) + } + /// Checks whether the selection is empty. pub fn is_empty(&self) -> bool { self.per_file.is_empty() && self.per_contract.is_empty() diff --git a/crates/solc-json-interface/src/standard_json/input/settings/selection/mod.rs b/crates/solc-json-interface/src/standard_json/input/settings/selection/mod.rs index 7ed0c94..486ec0b 100644 --- a/crates/solc-json-interface/src/standard_json/input/settings/selection/mod.rs +++ b/crates/solc-json-interface/src/standard_json/input/settings/selection/mod.rs @@ -44,15 +44,15 @@ impl PerFileSelection { Self { files } } - /// Returns whether `path` contains the `flag` or `None` if there is no selection for `path`. - pub fn contains(&self, path: &String, flag: &Flag) -> Option { + /// Checks whether `path` contains the `flag` or `None` if there is no selection for `path`. + pub fn contains(&self, path: &String, flag: Flag) -> Option { if let Some(file) = self.files.get(path) { return Some(file.contains(flag)); }; None } - /// Returns whether this is the empty per file selection. + /// Checks whether this is the empty per file selection. pub fn is_empty(&self) -> bool { self.files.is_empty() } @@ -60,8 +60,8 @@ impl PerFileSelection { /// Removes unneeded selections. pub fn retain(&mut self) { for file in self.files.values_mut() { - file.per_contract.retain(Flag::is_required_for_codegen); - file.per_file.retain(Flag::is_required_for_codegen); + file.per_contract.retain(|flag| !flag.is_evm_codegen()); + file.per_file.retain(|flag| !flag.is_evm_codegen()); } } } @@ -69,34 +69,53 @@ impl PerFileSelection { /// The `solc --standard-json` output selection. #[derive(Clone, Debug, Serialize, Deserialize, Default, PartialEq)] pub struct Selection { - /// Only the 'all' wildcard is available for robustness reasons. + /// Common configuration for all files. #[serde(default, rename = "*", skip_serializing_if = "FileSelection::is_empty")] - /// Individual file selection configuration, required for foundry. pub all: FileSelection, + /// Individual file selection configuration, required for foundry. #[serde(skip_serializing_if = "PerFileSelection::is_empty", flatten)] - files: PerFileSelection, + pub files: PerFileSelection, } impl Selection { - /// Creates the selection with arbitrary flags. - pub fn new(flags: Vec) -> Self { + /// Creates the selection for all contracts in all files with arbitrary `flags`. + pub fn new_all(flags: Vec) -> Self { Self { all: FileSelection::new(flags), files: Default::default(), } } - /// Creates the selection required by our compilation process. - pub fn new_required() -> Self { - Self::new(vec![ - Flag::AST, - Flag::MethodIdentifiers, - Flag::Metadata, - Flag::Yul, - ]) + /// Creates the selection required by our compilation process for all contracts in all files. + pub fn new_required_for_codegen_all() -> Self { + Self::new_all(Flag::codegen_requirements().into()) } - /// Creates the selection required for test compilation (includes EVM bytecode). + /// Creates the selection required by our compilation process for each contract in + /// `output_selection` requesting code generation. + pub fn new_required_for_codegen(output_selection: &Self) -> Self { + if output_selection.all.requests_codegen() { + return Self::new_required_for_codegen_all(); + } + + let mut files = PerFileSelection::default(); + for (file_name, file_selection) in &output_selection.files.files { + if file_selection.requests_codegen() { + files.files.insert( + file_name.to_owned(), + FileSelection::new_required_for_codegen(), + ); + } + } + + Self { + all: Default::default(), + files, + } + } + + /// Creates the selection required for test compilation (includes EVM bytecode) for all + /// contracts in all files. pub fn new_required_for_tests() -> Self { Self { all: FileSelection::new_required_for_tests(), @@ -106,7 +125,7 @@ impl Selection { /// Creates the selection required by Yul validation process. pub fn new_yul_validation() -> Self { - Self::new(vec![Flag::EVM]) + Self::new_all(vec![Flag::EVM]) } /// Extends the output selection with another one. @@ -116,10 +135,10 @@ impl Selection { self } - /// Returns flags that are going to be automatically added by the compiler, - /// but were not explicitly requested by the user. + /// Returns flags that were not explicitly requested by the user. /// - /// Afterwards, the flags are used to prune JSON output before returning it. + /// These flags are used to prune JSON output before returning it, + /// removing any output that was automatically added but not requested. pub fn selection_to_prune(&self) -> Self { Self { all: self.all.selection_to_prune(), @@ -127,8 +146,8 @@ impl Selection { } } - /// Whether the flag is requested. - pub fn contains(&self, path: &String, flag: &Flag) -> bool { + /// Checks whether the `flag` is requested. + pub fn contains(&self, path: &String, flag: Flag) -> bool { self.files .contains(path, flag) .unwrap_or(self.all.contains(flag)) @@ -136,8 +155,8 @@ impl Selection { /// Removes unneeded selections. pub fn retain(&mut self) { - self.all.per_file.retain(Flag::is_required_for_codegen); - self.all.per_contract.retain(Flag::is_required_for_codegen); + self.all.per_file.retain(|flag| !flag.is_evm_codegen()); + self.all.per_contract.retain(|flag| !flag.is_evm_codegen()); self.files.retain(); } } diff --git a/crates/solc-json-interface/src/standard_json/output/contract/mod.rs b/crates/solc-json-interface/src/standard_json/output/contract/mod.rs index 87f42bc..f6e9213 100644 --- a/crates/solc-json-interface/src/standard_json/output/contract/mod.rs +++ b/crates/solc-json-interface/src/standard_json/output/contract/mod.rs @@ -10,6 +10,9 @@ use std::collections::BTreeSet; use serde::Deserialize; use serde::Serialize; +#[cfg(feature = "resolc")] +use crate::SolcStandardJsonInputSettingsSelectionFileFlag; + use self::evm::EVM; /// The `solc --standard-json` output contract. @@ -81,4 +84,60 @@ impl Contract { && self.factory_dependencies.is_empty() && self.missing_libraries.is_empty() } + + /// Sets the field corresponding to the given `flag` to its default value, + /// resulting in the field being skipped during serialization. + pub fn reset_field_by_flag(&mut self, flag: SolcStandardJsonInputSettingsSelectionFileFlag) { + match flag { + SolcStandardJsonInputSettingsSelectionFileFlag::ABI => { + self.abi = Default::default(); + } + SolcStandardJsonInputSettingsSelectionFileFlag::Metadata => { + self.metadata = Default::default(); + } + SolcStandardJsonInputSettingsSelectionFileFlag::Devdoc => { + self.devdoc = Default::default(); + } + SolcStandardJsonInputSettingsSelectionFileFlag::Userdoc => { + self.userdoc = Default::default(); + } + SolcStandardJsonInputSettingsSelectionFileFlag::StorageLayout => { + self.storage_layout = Default::default(); + } + SolcStandardJsonInputSettingsSelectionFileFlag::Yul => { + self.ir_optimized = Default::default(); + } + SolcStandardJsonInputSettingsSelectionFileFlag::Ir => { + self.ir = Default::default(); + } + SolcStandardJsonInputSettingsSelectionFileFlag::EVM => { + self.evm = Default::default(); + } + SolcStandardJsonInputSettingsSelectionFileFlag::EVMBC => { + if let Some(evm) = self.evm.as_mut() { + evm.bytecode = Default::default(); + } + } + SolcStandardJsonInputSettingsSelectionFileFlag::EVMDBC => { + if let Some(evm) = self.evm.as_mut() { + evm.deployed_bytecode = Default::default(); + } + } + SolcStandardJsonInputSettingsSelectionFileFlag::Assembly => { + if let Some(evm) = self.evm.as_mut() { + evm.assembly_text = Default::default(); + } + } + SolcStandardJsonInputSettingsSelectionFileFlag::MethodIdentifiers => { + if let Some(evm) = self.evm.as_mut() { + evm.method_identifiers = Default::default(); + } + } + SolcStandardJsonInputSettingsSelectionFileFlag::AST + | SolcStandardJsonInputSettingsSelectionFileFlag::EVMLA => { + // Ignore AST (a per-file flag) and EVMLA + // as they have no contract field mappings. + } + } + } } diff --git a/crates/solc-json-interface/src/standard_json/output/mod.rs b/crates/solc-json-interface/src/standard_json/output/mod.rs index 76fd5e1..4b38152 100644 --- a/crates/solc-json-interface/src/standard_json/output/mod.rs +++ b/crates/solc-json-interface/src/standard_json/output/mod.rs @@ -63,7 +63,10 @@ impl Output { path.to_owned(), Source { id: index, - ast: source.content().map(|x| serde_json::to_value(x).unwrap()), + ast: source + .content() + .map(|x| serde_json::to_value(x).unwrap()) + .unwrap_or_default(), }, ) }) @@ -100,26 +103,20 @@ impl Output { mut self, selection_to_prune: SolcStandardJsonInputSettingsSelection, ) -> ! { + for (path, source) in self.sources.iter_mut() { + if selection_to_prune.contains( + path, + crate::SolcStandardJsonInputSettingsSelectionFileFlag::AST, + ) { + source.ast = Default::default(); + } + } + for (path, contracts) in self.contracts.iter_mut() { for contract in contracts.values_mut() { - if selection_to_prune.contains( - path, - &crate::SolcStandardJsonInputSettingsSelectionFileFlag::Metadata, - ) { - contract.metadata = serde_json::Value::Null; - } - if selection_to_prune.contains( - path, - &crate::SolcStandardJsonInputSettingsSelectionFileFlag::Yul, - ) { - contract.ir_optimized = String::new(); - } - if let Some(ref mut evm) = contract.evm { - if selection_to_prune.contains( - path, - &crate::SolcStandardJsonInputSettingsSelectionFileFlag::MethodIdentifiers, - ) { - evm.method_identifiers.clear(); + for &flag in crate::SolcStandardJsonInputSettingsSelectionFileFlag::all() { + if selection_to_prune.contains(path, flag) { + contract.reset_field_by_flag(flag); } } } @@ -153,11 +150,7 @@ impl Output { let messages: Vec = iter .flat_map(|(_path, source)| { - source - .ast - .as_ref() - .map(|ast| Source::get_messages(ast, &id_paths, sources, suppressed_warnings)) - .unwrap_or_default() + Source::get_messages(&source.ast, &id_paths, sources, suppressed_warnings) }) .collect(); self.errors.extend(messages); diff --git a/crates/solc-json-interface/src/standard_json/output/source.rs b/crates/solc-json-interface/src/standard_json/output/source.rs index b736122..f214501 100644 --- a/crates/solc-json-interface/src/standard_json/output/source.rs +++ b/crates/solc-json-interface/src/standard_json/output/source.rs @@ -20,7 +20,8 @@ pub struct Source { /// The source code ID. pub id: usize, /// The source code AST. - pub ast: Option, + #[serde(default, skip_serializing_if = "serde_json::Value::is_null")] + pub ast: serde_json::Value, } #[cfg(feature = "resolc")] @@ -29,7 +30,10 @@ impl Source { /// /// Is used for projects compiled without `solc`. pub fn new(id: usize) -> Self { - Self { id, ast: None } + Self { + id, + ast: Default::default(), + } } /// Checks the AST node for the usage of send or transfer address methods. diff --git a/docs/404.html b/docs/404.html index ef90f2f..aa4fd52 100644 --- a/docs/404.html +++ b/docs/404.html @@ -36,7 +36,7 @@ const path_to_root = ""; const default_light_theme = "light"; const default_dark_theme = "navy"; - window.path_to_searchindex_js = "searchindex-c7304031.js"; + window.path_to_searchindex_js = "searchindex-575cfd18.js"; diff --git a/docs/developer_guide.html b/docs/developer_guide.html index 5aa65f4..2e422fa 100644 --- a/docs/developer_guide.html +++ b/docs/developer_guide.html @@ -35,7 +35,7 @@ const path_to_root = ""; const default_light_theme = "light"; const default_dark_theme = "navy"; - window.path_to_searchindex_js = "searchindex-c7304031.js"; + window.path_to_searchindex_js = "searchindex-575cfd18.js"; diff --git a/docs/developer_guide/architecture.html b/docs/developer_guide/architecture.html index e994ce1..95e05e9 100644 --- a/docs/developer_guide/architecture.html +++ b/docs/developer_guide/architecture.html @@ -35,7 +35,7 @@ const path_to_root = "../"; const default_light_theme = "light"; const default_dark_theme = "navy"; - window.path_to_searchindex_js = "../searchindex-c7304031.js"; + window.path_to_searchindex_js = "../searchindex-575cfd18.js"; diff --git a/docs/developer_guide/contributing.html b/docs/developer_guide/contributing.html index d3d8bc1..7e0ff61 100644 --- a/docs/developer_guide/contributing.html +++ b/docs/developer_guide/contributing.html @@ -35,7 +35,7 @@ const path_to_root = "../"; const default_light_theme = "light"; const default_dark_theme = "navy"; - window.path_to_searchindex_js = "../searchindex-c7304031.js"; + window.path_to_searchindex_js = "../searchindex-575cfd18.js"; diff --git a/docs/developer_guide/cross_compilation.html b/docs/developer_guide/cross_compilation.html index bfe0fac..a5f0d77 100644 --- a/docs/developer_guide/cross_compilation.html +++ b/docs/developer_guide/cross_compilation.html @@ -35,7 +35,7 @@ const path_to_root = "../"; const default_light_theme = "light"; const default_dark_theme = "navy"; - window.path_to_searchindex_js = "../searchindex-c7304031.js"; + window.path_to_searchindex_js = "../searchindex-575cfd18.js"; diff --git a/docs/developer_guide/target.html b/docs/developer_guide/target.html index e68cb14..e8241c5 100644 --- a/docs/developer_guide/target.html +++ b/docs/developer_guide/target.html @@ -35,7 +35,7 @@ const path_to_root = "../"; const default_light_theme = "light"; const default_dark_theme = "navy"; - window.path_to_searchindex_js = "../searchindex-c7304031.js"; + window.path_to_searchindex_js = "../searchindex-575cfd18.js"; diff --git a/docs/developer_guide/testing.html b/docs/developer_guide/testing.html index 8bc8437..dd630df 100644 --- a/docs/developer_guide/testing.html +++ b/docs/developer_guide/testing.html @@ -35,7 +35,7 @@ const path_to_root = "../"; const default_light_theme = "light"; const default_dark_theme = "navy"; - window.path_to_searchindex_js = "../searchindex-c7304031.js"; + window.path_to_searchindex_js = "../searchindex-575cfd18.js"; diff --git a/docs/faq.html b/docs/faq.html index abf2285..2d5cdd1 100644 --- a/docs/faq.html +++ b/docs/faq.html @@ -35,7 +35,7 @@ const path_to_root = ""; const default_light_theme = "light"; const default_dark_theme = "navy"; - window.path_to_searchindex_js = "searchindex-c7304031.js"; + window.path_to_searchindex_js = "searchindex-575cfd18.js"; diff --git a/docs/index.html b/docs/index.html index 4fed031..03cbbb9 100644 --- a/docs/index.html +++ b/docs/index.html @@ -35,7 +35,7 @@ const path_to_root = ""; const default_light_theme = "light"; const default_dark_theme = "navy"; - window.path_to_searchindex_js = "searchindex-c7304031.js"; + window.path_to_searchindex_js = "searchindex-575cfd18.js"; diff --git a/docs/print.html b/docs/print.html index 8c2aca2..87d0346 100644 --- a/docs/print.html +++ b/docs/print.html @@ -36,7 +36,7 @@ const path_to_root = ""; const default_light_theme = "light"; const default_dark_theme = "navy"; - window.path_to_searchindex_js = "searchindex-c7304031.js"; + window.path_to_searchindex_js = "searchindex-575cfd18.js"; @@ -346,16 +346,16 @@ Please find our binary releas

There is remix IDE fork with resolc support at remix.polkadot.io. Unfortunately this is no longer actively maintained (there might be bugs and outdated resolc versions).

Standard JSON interface

-

The revive compiler is mostly compatible with the solc standard JSON interface. There are a few additional (PVM related) input configurations:

+

The revive compiler is mostly compatible with the solc standard JSON interface. There are a few differences and additional (PVM related) input configurations:

The settings.polkavm object

Used to configure PVM specific compiler settings.

settings.polkavm.debugInformation

A boolean value allowing to enable debug information. Corresponds to resolc -g.

The settings.polkavm.memoryConfig object

Used to apply PVM specific memory configuration settings.

-

settings.polkavm.memoryConifg.heapSize

+

settings.polkavm.memoryConfig.heapSize

A numerical value allowing to configure the contract heap size. Corresponds to resolc --heap-size.

-

settings.polkavm.memoryConifg.stackSize

+

settings.polkavm.memoryConfig.stackSize

A numerical value allowing to configure the contract stack size. Corresponds to resolc --stack-size.

The settings.optimizer object

The settings.optimizer object is augmented with support for PVM specific optimization settings.

@@ -363,6 +363,63 @@ Please find our binary releas

A single char value to configure the LLVM optimizer settings. Corresponds to resolc -O.

settings.llvmArguments

Allows to specify arbitrary command line arguments to LLVM initialization. Used mainly for development and debugging purposes.

+

The settings.outputSelection object

+

Used to select desired outputs.

+

The “all” (*) wildcard

+

Resolc supports the “all” (*) wildcard for the file-level (first-level) and contract-level (second-level) keys. A file-level key can be either the wildcard or a specific file name, whereas the contract-level key can only be the wildcard for robustness reasons.

+

Thus, output can be requested in 2 ways:

+
// All files and all contracts:
+{
+  "settings": {
+    "outputSelection": {
+      "*": {
+        "*": [/* specific contract-level output fields */],
+        "": [/* specific file-level output fields */]
+      }
+    }
+  }
+}
+
+// Specific files and all their contracts:
+{
+  "settings": {
+    "outputSelection": {
+      "path/to/my/file.sol": {
+        "*": [/* specific contract-level output fields */],
+        "": [/* specific file-level output fields */]
+      },
+      // Rest of files...
+    }
+  }
+}
+
+

The contract-level evm output selection

+
+

Note

+

Currently, resolc supports requesting either the full evm output, or one more level of specificity, such as evm.bytecode.

+
+

When requesting code generation, such as evm.bytecode or evm.assembly, the resolc compilation process additionally needs ast, metadata, irOptimized, and evm.methodIdentifiers selectors. These selectors will be automatically added if code generation is needed, but will only be included in the output if explicitly requested.

+
{
+  "settings": {
+    "outputSelection": {
+      "path/to/my/file1.sol": {
+        // Contracts in this file will generate bytecode.
+        // Only these fields of the JSON output selection will be in the `contracts` output.
+        "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"],
+        // Only this field of the JSON output selection will be in the `sources` output.
+        "": ["ast"]
+      },
+      "path/to/my/file2.sol": {
+        // No contracts in this file will generate bytecode.
+        "*": ["abi", "evm.methodIdentifiers", "metadata"],
+        // No `ast` will be in the `sources` output (only the automatically added `id`,
+        // similar to solc as this is not a configurable output selection).
+        "": []
+      },
+    }
+  }
+}
+

Differences to EVM

This section highlights some potentially observable differences in the YUL EVM dialect translation compared to Ethereum Solidity.

diff --git a/docs/revive_runner.html b/docs/revive_runner.html index d3d5d44..716a5de 100644 --- a/docs/revive_runner.html +++ b/docs/revive_runner.html @@ -35,7 +35,7 @@ const path_to_root = ""; const default_light_theme = "light"; const default_dark_theme = "navy"; - window.path_to_searchindex_js = "searchindex-c7304031.js"; + window.path_to_searchindex_js = "searchindex-575cfd18.js"; diff --git a/docs/roadmap.html b/docs/roadmap.html index 7812b92..09284ac 100644 --- a/docs/roadmap.html +++ b/docs/roadmap.html @@ -35,7 +35,7 @@ const path_to_root = ""; const default_light_theme = "light"; const default_dark_theme = "navy"; - window.path_to_searchindex_js = "searchindex-c7304031.js"; + window.path_to_searchindex_js = "searchindex-575cfd18.js"; diff --git a/docs/searcher-c2a407aa.js b/docs/searcher-c2a407aa.js index ccbecc6..ead5e06 100644 --- a/docs/searcher-c2a407aa.js +++ b/docs/searcher-c2a407aa.js @@ -437,7 +437,7 @@ window.search = window.search || {}; if (yes) { loadSearchScript( window.path_to_searchindex_js || - path_to_root + 'searchindex-c7304031.js', + path_to_root + 'searchindex-575cfd18.js', 'mdbook-search-index'); search_wrap.classList.remove('hidden'); searchicon.setAttribute('aria-expanded', 'true'); diff --git a/docs/searchindex-575cfd18.js b/docs/searchindex-575cfd18.js new file mode 100644 index 0000000..ddd3ec2 --- /dev/null +++ b/docs/searchindex-575cfd18.js @@ -0,0 +1 @@ +window.search = Object.assign(window.search, JSON.parse('{"doc_urls":["welcome.html#welcome","welcome.html#target-audience","welcome.html#other-polkadot-contracts-resources","welcome.html#about","user_guide.html#resolc-user-guide","user_guide.html#revive-vs-resolc-nomenclature","user_guide/installation.html#installation","user_guide/installation.html#resolc-binary-releases","user_guide/installation.html#installing-the-solc-dependency","user_guide/installation.html#revive-npm-package","user_guide/installation.html#buidling-resolc-from-source","user_guide/cli.html#cli-usage","user_guide/cli.html#llvm-optimization-levels","user_guide/cli.html#stack-size","user_guide/cli.html#heap-size","user_guide/cli.html#solc","user_guide/cli.html#debug-artifacts","user_guide/cli.html#debug-info","user_guide/cli.html#deploy-time-linking","user_guide/js.html#js-npm-package","user_guide/tooling.html#tooling-integration","user_guide/tooling.html#solidity-toolkits","user_guide/tooling.html#compiler-explorer","user_guide/tooling.html#remix-ide","user_guide/std_json.html#standard-json-interface","user_guide/std_json.html#the-settingspolkavm-object","user_guide/std_json.html#settingspolkavmdebuginformation","user_guide/std_json.html#the-settingspolkavmmemoryconfig-object","user_guide/std_json.html#the-settingsoptimizer-object","user_guide/std_json.html#settingsoptimizermode","user_guide/std_json.html#settingsllvmarguments","user_guide/std_json.html#the-settingsoutputselection-object","user_guide/std_json.html#the-all--wildcard","user_guide/std_json.html#the-contract-level-evm-output-selection","user_guide/differences.html#differences-to-evm","user_guide/differences.html#deploy-code-vs-runtime-code","user_guide/differences.html#solidity","user_guide/differences.html#the-6364-gas-rule","user_guide/differences.html#addresscreationcode","user_guide/differences.html#yul-functions","user_guide/differences.html#mload-mstore-msize-mcopy-memory-related-functions","user_guide/differences.html#calldataload-calldatacopy","user_guide/differences.html#codecopy","user_guide/differences.html#create-create2","user_guide/differences.html#dataoffset","user_guide/differences.html#datasize","user_guide/differences.html#revert-return","user_guide/differences.html#prevrandao-difficulty","user_guide/differences.html#pc-extcodecopy","user_guide/differences.html#blobhash-blobbasefee","user_guide/differences.html#difference-regarding-the-solc-via-ir-mode","user_guide/differences.html#example-state-variable-initialization-order-in-inheritance","user_guide/rust_libraries.html#rust-contract-libraries","revive_runner.html#revive-runner-sandbox","revive_runner.html#installation-and-usage","revive_runner.html#trace-logs","revive_runner.html#automatic-contract-instantiation","revive_runner.html#example","developer_guide.html#developer-guide","developer_guide/contributing.html#contributor-guide","developer_guide/contributing.html#getting-started","developer_guide/contributing.html#using-the-makefile","developer_guide/contributing.html#codebase-organization","developer_guide/contributing.html#contribution-rules","developer_guide/contributing.html#style-guide","developer_guide/contributing.html#ai-policy","developer_guide/architecture.html#compiler-architecture-and-internals","developer_guide/architecture.html#resolc","developer_guide/architecture.html#reproducible-contract-builds","developer_guide/architecture.html#the-revive-compiler-libraries","developer_guide/architecture.html#evm-heap-memory","developer_guide/architecture.html#the-llvm-dependency","developer_guide/architecture.html#custom-optimizations","developer_guide/target.html#pvm-and-the-pallet-revive-runtime-target","developer_guide/target.html#target-cpu-configuration","developer_guide/target.html#why-pvm","developer_guide/target.html#host-environment-pallet-revive","developer_guide/testing.html#testing-strategy","developer_guide/testing.html#bug-compatibility-with-ethereum-solidity","developer_guide/testing.html#differential-integration-tests","developer_guide/testing.html#the-differential-testing-utility","developer_guide/cross_compilation.html#cross-compilation","developer_guide/cross_compilation.html#wasm-via-emscripten","developer_guide/cross_compilation.html#musl-libc","faq.html#faq","faq.html#what-evm-version-do-you-support","faq.html#is-inline-assembly-supported","faq.html#do-you-support-opcode-xy","faq.html#in-what-solidity-version-should-i-write-my-dapp","faq.html#tool-xy-says-the-contract-size-is-larger-than-24kb-and-will-fail-to-deploy","faq.html#is-resolc-a-drop-in-replacement-for-solc","roadmap.html#vision-and-roadmap","roadmap.html#roadmap"],"index":{"documentStore":{"docInfo":{"0":{"body":74,"breadcrumbs":2,"title":1},"1":{"body":22,"breadcrumbs":3,"title":2},"10":{"body":6,"breadcrumbs":7,"title":3},"11":{"body":33,"breadcrumbs":8,"title":2},"12":{"body":53,"breadcrumbs":9,"title":3},"13":{"body":62,"breadcrumbs":8,"title":2},"14":{"body":75,"breadcrumbs":8,"title":2},"15":{"body":10,"breadcrumbs":7,"title":1},"16":{"body":26,"breadcrumbs":8,"title":2},"17":{"body":15,"breadcrumbs":8,"title":2},"18":{"body":236,"breadcrumbs":9,"title":3},"19":{"body":31,"breadcrumbs":9,"title":3},"2":{"body":7,"breadcrumbs":4,"title":3},"20":{"body":9,"breadcrumbs":7,"title":2},"21":{"body":14,"breadcrumbs":7,"title":2},"22":{"body":11,"breadcrumbs":7,"title":2},"23":{"body":14,"breadcrumbs":7,"title":2},"24":{"body":15,"breadcrumbs":9,"title":3},"25":{"body":6,"breadcrumbs":8,"title":2},"26":{"body":9,"breadcrumbs":7,"title":1},"27":{"body":31,"breadcrumbs":8,"title":2},"28":{"body":8,"breadcrumbs":8,"title":2},"29":{"body":10,"breadcrumbs":7,"title":1},"3":{"body":15,"breadcrumbs":1,"title":0},"30":{"body":13,"breadcrumbs":7,"title":1},"31":{"body":4,"breadcrumbs":8,"title":2},"32":{"body":63,"breadcrumbs":7,"title":1},"33":{"body":83,"breadcrumbs":11,"title":5},"34":{"body":23,"breadcrumbs":7,"title":2},"35":{"body":41,"breadcrumbs":10,"title":5},"36":{"body":6,"breadcrumbs":6,"title":1},"37":{"body":18,"breadcrumbs":8,"title":3},"38":{"body":5,"breadcrumbs":6,"title":1},"39":{"body":58,"breadcrumbs":7,"title":2},"4":{"body":43,"breadcrumbs":6,"title":3},"40":{"body":64,"breadcrumbs":12,"title":7},"41":{"body":16,"breadcrumbs":7,"title":2},"42":{"body":3,"breadcrumbs":6,"title":1},"43":{"body":101,"breadcrumbs":7,"title":2},"44":{"body":3,"breadcrumbs":6,"title":1},"45":{"body":7,"breadcrumbs":6,"title":1},"46":{"body":8,"breadcrumbs":7,"title":2},"47":{"body":4,"breadcrumbs":7,"title":2},"48":{"body":10,"breadcrumbs":7,"title":2},"49":{"body":20,"breadcrumbs":7,"title":2},"5":{"body":52,"breadcrumbs":7,"title":4},"50":{"body":24,"breadcrumbs":11,"title":6},"51":{"body":57,"breadcrumbs":11,"title":6},"52":{"body":167,"breadcrumbs":9,"title":3},"53":{"body":36,"breadcrumbs":6,"title":3},"54":{"body":21,"breadcrumbs":5,"title":2},"55":{"body":38,"breadcrumbs":5,"title":2},"56":{"body":15,"breadcrumbs":6,"title":3},"57":{"body":120,"breadcrumbs":4,"title":1},"58":{"body":11,"breadcrumbs":4,"title":2},"59":{"body":11,"breadcrumbs":6,"title":2},"6":{"body":24,"breadcrumbs":5,"title":1},"60":{"body":8,"breadcrumbs":6,"title":2},"61":{"body":39,"breadcrumbs":6,"title":2},"62":{"body":85,"breadcrumbs":6,"title":2},"63":{"body":44,"breadcrumbs":6,"title":2},"64":{"body":107,"breadcrumbs":6,"title":2},"65":{"body":112,"breadcrumbs":6,"title":2},"66":{"body":58,"breadcrumbs":7,"title":3},"67":{"body":55,"breadcrumbs":5,"title":1},"68":{"body":76,"breadcrumbs":7,"title":3},"69":{"body":65,"breadcrumbs":7,"title":3},"7":{"body":21,"breadcrumbs":7,"title":3},"70":{"body":57,"breadcrumbs":7,"title":3},"71":{"body":69,"breadcrumbs":6,"title":2},"72":{"body":54,"breadcrumbs":6,"title":2},"73":{"body":9,"breadcrumbs":12,"title":5},"74":{"body":14,"breadcrumbs":10,"title":3},"75":{"body":199,"breadcrumbs":8,"title":1},"76":{"body":34,"breadcrumbs":11,"title":4},"77":{"body":63,"breadcrumbs":6,"title":2},"78":{"body":34,"breadcrumbs":8,"title":4},"79":{"body":187,"breadcrumbs":7,"title":3},"8":{"body":13,"breadcrumbs":7,"title":3},"80":{"body":73,"breadcrumbs":7,"title":3},"81":{"body":19,"breadcrumbs":6,"title":2},"82":{"body":69,"breadcrumbs":7,"title":3},"83":{"body":12,"breadcrumbs":6,"title":2},"84":{"body":0,"breadcrumbs":2,"title":1},"85":{"body":12,"breadcrumbs":4,"title":3},"86":{"body":10,"breadcrumbs":4,"title":3},"87":{"body":4,"breadcrumbs":4,"title":3},"88":{"body":25,"breadcrumbs":5,"title":4},"89":{"body":13,"breadcrumbs":9,"title":8},"9":{"body":5,"breadcrumbs":7,"title":3},"90":{"body":9,"breadcrumbs":5,"title":4},"91":{"body":66,"breadcrumbs":4,"title":2},"92":{"body":49,"breadcrumbs":3,"title":1}},"docs":{"0":{"body":"Hello and a warm welcome to the revive Solidity compiler book! Warning Solidity on PVM is running on the pallet-revive runtime. This introduces observable semantic differences in comparison with the EVM. Study the differences section carefully. Ignoring these differences may lead to defunct contracts. Notable examples: The 63/64 gas rule isn’t implemented in the pallet (introduces potential DoS vector when calling other contracts) Contract instantiation works differently (by hash instead of by code) The gas model implemented by pallet-revive differs from Ethereum The heap size is fixed instead of gas-metered and there’s a fixed amount of stack size (contracts working fine on EVM may trap on PVM)","breadcrumbs":"Welcome » Welcome","id":"0","title":"Welcome"},"1":{"body":"Solidity dApp developers should read the user guide. Solidity on PolkaVM introduces important differences to EVM which should be well understood. Contributors will find the developer guide helpful for getting up to speed.","breadcrumbs":"Welcome » Target audience","id":"1","title":"Target audience"},"10":{"body":"Please follow the build instructions in the revive README.md.","breadcrumbs":"resolc user guide » Installation » Buidling resolc from source","id":"10","title":"Buidling resolc from source"},"11":{"body":"We aim to keep the resolc CLI usage close to solc. There are a few things and options worthwhile to know about in resolc which do not exist in the Ethereum world. This chapter explains those in more detail than the CLI help message. Tip For the complete help about CLI options, please see resolc --help.","breadcrumbs":"resolc user guide » Command Line Interface » CLI usage","id":"11","title":"CLI usage"},"12":{"body":"-O, --optimization resolc exposes the optimization level setting for the LLVM backend. The performance and size of compiled contracts varies wiedly between different optimization levels. Valid levels are the following: 0: No optimizations are applied. 1: Basic optimizations for execution time. 2: Advanced optimizations for execution time. 3: Aggressive optimizations for execution time. s: Optimize for code size. z: Aggressively optimize for code size. By default, -Oz is applied.","breadcrumbs":"resolc user guide » Command Line Interface » LLVM optimization levels","id":"12","title":"LLVM optimization levels"},"13":{"body":"--stack-size PVM is a register machine with a traditional stack memory space for local variables. This controls the total amount of stack space the contract can use. You are incentivized to keep this value as small as possible: Increasing the stack size will increase gas costs due to increased startup costs. The stack size contributes to the total memory size a contract can use, which includes the contract’s code size. Default value: 131072 Warning If the contract uses more stack memory than configured, it will compile fine but eventually revert execution at runtime!","breadcrumbs":"resolc user guide » Command Line Interface » Stack size","id":"13","title":"Stack size"},"14":{"body":"--heap-size Unlike the EVM, due to the lack of dynamic memory metering, PVM contracts emulate the EVM heap memory with a static buffer. Consequentially, instead of infinite memory with exponentially growing gas costs, PVM contracts have a finite amount of memory with constant gas costs available. You are incentivized to keep this value as small as possible:\\n1.Increasing the heap size will increase startup costs.\\n2.The heap size contributes to the total memory size a contract can use, which includes the contract’s code size Default value: 131072 Warning If the contract uses more heap memory than configured, it will compile fine but eventually revert execution at runtime!","breadcrumbs":"resolc user guide » Command Line Interface » Heap size","id":"14","title":"Heap size"},"15":{"body":"--solc Specify the path to the solc executable. By default, the one in ${PATH} is used.","breadcrumbs":"resolc user guide » Command Line Interface » solc","id":"15","title":"solc"},"16":{"body":"--debug-output-dir Dump all intermediary compiler artifacts to files in the specified directory. This includes the YUL IR, optimized and unoptimized LLVM IR, the ELF object and the PVM assembly. Useful for debugging and development purposes.","breadcrumbs":"resolc user guide » Command Line Interface » Debug artifacts","id":"16","title":"Debug artifacts"},"17":{"body":"-g Generate source based debug information in the output code file. Useful for debugging and development purposes and disabled by default.","breadcrumbs":"resolc user guide » Command Line Interface » Debug info","id":"17","title":"Debug info"},"18":{"body":"--link [--libraries ] In Solidity, 3 things can happen with libraries: They are not externally callable and thus can be inlined. The solc Solidity optimizer inlines those (usually the case). Note: resolc always activates the solc Solidity optimizer. If the solc Solidity optimizer is disabled or for some reason fails to inline them (both rare), they are not inlined and require linking. They are externally callable but still linked at compile time. This is the case if at compile time the library address is known (i.e. --libraries supplied in CLI or the corresponding setting in STD JSON input). They are linked at deploy time. This happens when the compiler does not know the library address (i.e. --libraries flag is missing or the provided libraries are incomplete, same for STD JSON input). This case is rare because it’s discourage and should never be used by production dApps. In cases 1.2 and 3: Some of the produced code blobs will be in the “unlinked” raw ELF object format and not yet deployable. To make them deployable, they need to be “linked” (done using the resolc --link linker mode explained below). The compiler emitted DELEGATECALL instructions to call non-inlined (unlinked) libraries. The contract deployer must make sure to deploy any libraries prior to contract deployment. Warning Using deploy time linking is officially discouraged. Mainly due to bytecode hashes changing after the fact. We decided to support it in resolc regardless, due to popular request. Similar to how it works in solc, --libraries may be used to provide libraries during linking mode. Unlike with solc, where linking implies a simple string substitution mechanism, resolc needs to resolve actual missing ELF symbols. This is due to how factory dependencies work in PVM. As a consequence, it isn’t sufficient to just provide the unlinked blobs to the linker. Instead, they must be provided in the exact same directory structure the Solidity source code was found during compile time. Example: The contract src/foo/bar.sol:Bar is involved in deploy time linking. It may be a factory dependency. The contract blob needs to be provided inside a relative src/foo/ directory to --link. Otherwise symbol resolution may fail. Note Tooling is supposed to take care of this. In the future, we may append explicit linkage data to simplify the deploy time linking feature.","breadcrumbs":"resolc user guide » Command Line Interface » Deploy time linking","id":"18","title":"Deploy time linking"},"19":{"body":"The resolc compiler driver is published as an NPM package under @parity/resolc. It’s usable from Node.js code or directly from the command line: npx @parity/resolc@latest --bin crates/integration/contracts/flipper.sol -o /tmp/out Note While the npm package makes a nice portable option, it doesn’t expose all options.","breadcrumbs":"resolc user guide » JS NPM package » JS NPM package","id":"19","title":"JS NPM package"},"2":{"body":"Head to contracts.polkadot.io for more general information about contracts on Polkadot.","breadcrumbs":"Welcome » Other Polkadot contracts resources","id":"2","title":"Other Polkadot contracts resources"},"20":{"body":"resolc achieved successful integration with a variety of third party developer tools.","breadcrumbs":"resolc user guide » Tooling integration » Tooling integration","id":"20","title":"Tooling integration"},"21":{"body":"Support for resolc is available in forks of the hardhat and foundry Solidity toolkits: The Parity Hardhat fork The Parity Foundry fork","breadcrumbs":"resolc user guide » Tooling integration » Solidity toolkits","id":"21","title":"Solidity toolkits"},"22":{"body":"resolc is available on godbolt.org for the Solidity and Yul input languages. See also the announcement post on the forum.","breadcrumbs":"resolc user guide » Tooling integration » Compiler explorer","id":"22","title":"Compiler explorer"},"23":{"body":"There is remix IDE fork with resolc support at remix.polkadot.io. Unfortunately this is no longer actively maintained (there might be bugs and outdated resolc versions).","breadcrumbs":"resolc user guide » Tooling integration » Remix IDE","id":"23","title":"Remix IDE"},"24":{"body":"The revive compiler is mostly compatible with the solc standard JSON interface. There are a few differences and additional (PVM related) input configurations:","breadcrumbs":"resolc user guide » Standard JSON interface » Standard JSON interface","id":"24","title":"Standard JSON interface"},"25":{"body":"Used to configure PVM specific compiler settings.","breadcrumbs":"resolc user guide » Standard JSON interface » The settings.polkavm object","id":"25","title":"The settings.polkavm object"},"26":{"body":"A boolean value allowing to enable debug information. Corresponds to resolc -g.","breadcrumbs":"resolc user guide » Standard JSON interface » settings.polkavm.debugInformation","id":"26","title":"settings.polkavm.debugInformation"},"27":{"body":"Used to apply PVM specific memory configuration settings. settings.polkavm.memoryConfig.heapSize A numerical value allowing to configure the contract heap size. Corresponds to resolc --heap-size. settings.polkavm.memoryConfig.stackSize A numerical value allowing to configure the contract stack size. Corresponds to resolc --stack-size.","breadcrumbs":"resolc user guide » Standard JSON interface » The settings.polkavm.memoryConfig object","id":"27","title":"The settings.polkavm.memoryConfig object"},"28":{"body":"The settings.optimizer object is augmented with support for PVM specific optimization settings.","breadcrumbs":"resolc user guide » Standard JSON interface » The settings.optimizer object","id":"28","title":"The settings.optimizer object"},"29":{"body":"A single char value to configure the LLVM optimizer settings. Corresponds to resolc -O.","breadcrumbs":"resolc user guide » Standard JSON interface » settings.optimizer.mode","id":"29","title":"settings.optimizer.mode"},"3":{"body":"This mdBook documents the revive Solidity compiler project. The content is found under book/. Run make book to observe changes.","breadcrumbs":"Welcome » About","id":"3","title":"About"},"30":{"body":"Allows to specify arbitrary command line arguments to LLVM initialization. Used mainly for development and debugging purposes.","breadcrumbs":"resolc user guide » Standard JSON interface » settings.llvmArguments","id":"30","title":"settings.llvmArguments"},"31":{"body":"Used to select desired outputs.","breadcrumbs":"resolc user guide » Standard JSON interface » The settings.outputSelection object","id":"31","title":"The settings.outputSelection object"},"32":{"body":"Resolc supports the “all” ( *) wildcard for the file-level (first-level) and contract-level (second-level) keys. A file-level key can be either the wildcard or a specific file name, whereas the contract-level key can only be the wildcard for robustness reasons. Thus, output can be requested in 2 ways: // All files and all contracts:\\n{ \\"settings\\": { \\"outputSelection\\": { \\"*\\": { \\"*\\": [/* specific contract-level output fields */], \\"\\": [/* specific file-level output fields */] } } }\\n} // Specific files and all their contracts:\\n{ \\"settings\\": { \\"outputSelection\\": { \\"path/to/my/file.sol\\": { \\"*\\": [/* specific contract-level output fields */], \\"\\": [/* specific file-level output fields */] }, // Rest of files... } }\\n}","breadcrumbs":"resolc user guide » Standard JSON interface » The “all” ( *) wildcard","id":"32","title":"The “all” ( *) wildcard"},"33":{"body":"Note Currently, resolc supports requesting either the full evm output, or one more level of specificity, such as evm.bytecode. When requesting code generation, such as evm.bytecode or evm.assembly, the resolc compilation process additionally needs ast, metadata, irOptimized, and evm.methodIdentifiers selectors. These selectors will be automatically added if code generation is needed, but will only be included in the output if explicitly requested. { \\"settings\\": { \\"outputSelection\\": { \\"path/to/my/file1.sol\\": { // Contracts in this file will generate bytecode. // Only these fields of the JSON output selection will be in the `contracts` output. \\"*\\": [\\"abi\\", \\"evm.methodIdentifiers\\", \\"metadata\\", \\"evm.bytecode\\"], // Only this field of the JSON output selection will be in the `sources` output. \\"\\": [\\"ast\\"] }, \\"path/to/my/file2.sol\\": { // No contracts in this file will generate bytecode. \\"*\\": [\\"abi\\", \\"evm.methodIdentifiers\\", \\"metadata\\"], // No `ast` will be in the `sources` output (only the automatically added `id`, // similar to solc as this is not a configurable output selection). \\"\\": [] }, } }\\n}","breadcrumbs":"resolc user guide » Standard JSON interface » The contract-level evm output selection","id":"33","title":"The contract-level evm output selection"},"34":{"body":"This section highlights some potentially observable differences in the YUL EVM dialect translation compared to Ethereum Solidity. Solidity developers deploying dApps to pallet-revive ought to read and understand this section well.","breadcrumbs":"resolc user guide » Differences to EVM » Differences to EVM","id":"34","title":"Differences to EVM"},"35":{"body":"Our contract runtime does not differentiate between runtime code and deploy (constructor) code.\\nInstead, both are emitted into a single PVM contract code blob and live on-chain.\\nTherefore, in EVM terminology, the deploy code equals the runtime code. Tip In constructor code, the codesize instruction will return the call data size instead of the actual code blob size.","breadcrumbs":"resolc user guide » Differences to EVM » Deploy code vs. runtime code","id":"35","title":"Deploy code vs. runtime code"},"36":{"body":"We are aware of the following differences in the translation of Solidity code.","breadcrumbs":"resolc user guide » Differences to EVM » Solidity","id":"36","title":"Solidity"},"37":{"body":"pallet-revive doesn’t apply the 63/64 gas rule. We strongly advice to change any code calling untrusted contracts to supply a limited amount of gas only!","breadcrumbs":"resolc user guide » Differences to EVM » The 63/64 gas rule","id":"37","title":"The 63/64 gas rule"},"38":{"body":"This returns the bytecode keccak256 hash instead.","breadcrumbs":"resolc user guide » Differences to EVM » address.creationCode","id":"38","title":"address.creationCode"},"39":{"body":"The below list contains noteworthy differences in the translation of YUL functions. Note Many functions receive memory buffer offset pointer or size arguments. The PVM pointer size is 32 bit, supplying memory offset or buffer size values above 2^32-1 may lead to OutOfGas errors trap contract execution. The solc compiler ought to always emit valid memory references, so Solidity dApp authors don’t need to worry about this unless they deal with low level assembly code.","breadcrumbs":"resolc user guide » Differences to EVM » YUL functions","id":"39","title":"YUL functions"},"4":{"body":"resolc is a Solidity v0.8 compiler for Polkadot native smart contracts. Solidity compiled with resolc targets PolaVM (PVM). Thanks to additional compiler optimizations and the PVM JIT, contract code can execute much faster than the EVM equivalent. resolc supports almost all Solidity v0.8 features including inline assembly, offering a high level of comptability with the Ethereum Solidity reference implementation.","breadcrumbs":"resolc user guide » resolc user guide","id":"4","title":"resolc user guide"},"40":{"body":"In general, revive preserves the memory layout, meaning low level memory operations are supported. However, a few caveats apply: The EVM linear heap memory is emulated using a fixed byte buffer of 128kb. This implies that the maximum memory a contract can use is limited to 128kb (on Ethereum, contract memory is capped by gas and therefore varies). Thus, accessing memory offsets larger than the fixed buffer size will trap the contract at runtime with an OutOfBound error. The compiler might detect and optimize unused memory reads and writes, leading to a different msize compared to what the EVM would see.","breadcrumbs":"resolc user guide » Differences to EVM » mload, mstore, msize, mcopy (memory related functions)","id":"40","title":"mload, mstore, msize, mcopy (memory related functions)"},"41":{"body":"In the constructor code, the offset is ignored and this always returns 0. Warning pallet-revive restricts the calldata size (to 128kb at the time of writing).","breadcrumbs":"resolc user guide » Differences to EVM » calldataload, calldatacopy","id":"41","title":"calldataload, calldatacopy"},"42":{"body":"Only supported in constructor code.","breadcrumbs":"resolc user guide » Differences to EVM » codecopy","id":"42","title":"codecopy"},"43":{"body":"Deployments on revive work different than on EVM. In a nutshell: Instead of supplying the deploy code concatenated with the constructor arguments (the EVM deploy model), the revive runtime expects two pointers: A buffer containing the code hash to deploy. The constructor arguments buffer. To make contract instantiation using the new keyword in Solidity work seamlessly, revive translates the dataoffset and datasize instructions so that they assume the contract hash instead of the contract code.\\nThe hash is always of constant size.\\nThus, revive is able to supply the expected code hash and constructor arguments pointer to the runtime. Warning This might fall apart in code creating contracts inside assembly blocks. We strongly discourage using the create family opcodes to manually craft deployments in assembly blocks! Usually, the reason for using assembly blocks is to save gas, which is likely futile on revive due to the underlying differences in the VM architectures, gas models and transaction costs.","breadcrumbs":"resolc user guide » Differences to EVM » create, create2","id":"43","title":"create, create2"},"44":{"body":"Returns the contract hash.","breadcrumbs":"resolc user guide » Differences to EVM » dataoffset","id":"44","title":"dataoffset"},"45":{"body":"Returns the contract hash size (constant value of 32).","breadcrumbs":"resolc user guide » Differences to EVM » datasize","id":"45","title":"datasize"},"46":{"body":"pallet-revive restricts the returndata size (to 128kb at the time of writing).","breadcrumbs":"resolc user guide » Differences to EVM » revert, return","id":"46","title":"revert, return"},"47":{"body":"Translates to a constant value of 2500000000000000.","breadcrumbs":"resolc user guide » Differences to EVM » prevrandao, difficulty","id":"47","title":"prevrandao, difficulty"},"48":{"body":"Only valid to use in EVM (they also have no use case in PVM) and produce a compile time error.","breadcrumbs":"resolc user guide » Differences to EVM » pc, extcodecopy","id":"48","title":"pc, extcodecopy"},"49":{"body":"Related to the Ethereum rollup model and produce a compile time error. Polkadot offers a superior rollup model, removing the use case for blob data related opcodes.","breadcrumbs":"resolc user guide » Differences to EVM » blobhash, blobbasefee","id":"49","title":"blobhash, blobbasefee"},"5":{"body":"revive is the name of the overarching “Solidity to PolkaVM” compiler project, which contains multiple components (for example the Yul parser, the code generation library, the resolc executable itself, and many more things). resolc is the name of the compiler driver executable, combining many revive components in a single and easy to use binary application. In other words, revive is the whole compiler infrastructure (more like LLVM) and resolc is a user-facing single-entrypoint compiler frontend (more like clang).","breadcrumbs":"resolc user guide » revive vs. resolc nomenclature","id":"5","title":"revive vs. resolc nomenclature"},"50":{"body":"There are two different compilation pipelines available in solc and there are small differences between them. Since resolc processes the YUL IR, always assume the solc IR based codegen behavior for contracts compiled with the revive compiler.","breadcrumbs":"resolc user guide » Differences to EVM » Difference regarding the solc via-ir mode","id":"50","title":"Difference regarding the solc via-ir mode"},"51":{"body":"With via-ir, base constructors run before derived state variables are initialized: contract InnerContract { uint public innerConstructedStartTokenId; constructor() { innerConstructedStartTokenId = _startTokenId(); } function _startTokenId() internal view virtual returns (uint) { return 0; }\\n} contract Test is InnerContract { uint public START_TOKEN_ID = 1; constructor() InnerContract() { } function _startTokenId() internal view virtual override returns (uint) { return START_TOKEN_ID; }\\n} Here, innerConstructedStartTokenId in Test returns 0 (with legacy EVM codegen it’d return 1).","breadcrumbs":"resolc user guide » Differences to EVM » Example: State variable initialization order in inheritance","id":"51","title":"Example: State variable initialization order in inheritance"},"52":{"body":"Note This is not yet implemented but something for consideration on the roadmap. Solidity - tightly coupled to the EVM - introduces some inherent inefficiencies that are by design and either needs to be followed or can’t be easily worked around, even with efforts like better optimized compiler and VM implementations. This represents a technical dead end. So far the EVM sees no adoption beyond the blockchain industry. Chances are that the EVM end up deprecated for technical reasons (or maybe not and the RISC-V idea gets abandoned, who knows). PVM, however, is a general purpose VM. It supports LLVM based mainstream programming languages like Rust. It’s a common software engineering practice to compose applications from pieces written in multiple languages, using each to their own strength. For example, AI solutions traditionally use the python scripting language for convenient developer experience, while the underlying AI models get implemented in a lower level language such as C++. The same pattern can of course be applied to dApps, where we’d expect application specific languages like Solidity mixed with libraries implementing computationally complex algorithms in a lower level language. Business logic and user interfaces are naturally implemented as regular Solidity dApps which can include (link against) Rust libraries. Rust is a fast, safe low level language and the Polkadot SDK is written in Rust itself, making it an excellent choice. For example, ZK proof verifiers or expensive DeFi primitives would benefit greatly from Rust implementations. revive provides tooling support and a small Rust contracts SDK for seamless integration with Rust libraries.","breadcrumbs":"resolc user guide » Rust contract libraries » Rust contract libraries","id":"52","title":"Rust contract libraries"},"53":{"body":"Running contract code usually requires a blockchain node. While local dev nodes can be used, sometimes it’s just not desirable to do so. Instead, it can be much more convenient to run and debug contract code with a stripped down environment. This is where the revive-runner comes in handy. In a nutshell, it is a single-binary no-blockchain pallet-revive runtime.","breadcrumbs":"revive-runner sandbox » revive-runner sandbox","id":"53","title":"revive-runner sandbox"},"54":{"body":"Inside the root revive repository directory, install it from source (requires Rust installed): make install-revive-runner After installing, see revive-runner --help for usage help.","breadcrumbs":"revive-runner sandbox » Installation and usage","id":"54","title":"Installation and usage"},"55":{"body":"The standard RUST_LOG environment variable controls the log output from the contract execution. This includes revive runtime logs and PVM execution trace logs. Sometimes it’s convenient to have more fine granular insight. Some useful filters: RUST_LOG=runtime=trace: The pallet-revive runtime trace logs. RUST_LOG=polkavm=trace: Low level PolkaVM instruction tracing.","breadcrumbs":"revive-runner sandbox » Trace logs","id":"55","title":"Trace logs"},"56":{"body":"To avoid running the constract in an unitialized state, revive-runner automatically instantiates the contract before calling it (constructor arguments can be provided).","breadcrumbs":"revive-runner sandbox » Automatic contract instantiation","id":"56","title":"Automatic contract instantiation"},"57":{"body":"Suppose we want to trace the syscalls of the execution of a compiled contract file Flipper.pvm: RUST_LOG=runtime=trace revive-runner -f Flipper.pvm\\n[DEBUG runtime::revive] Contract memory usage: purgable=6144/3145728 KB baseline=103063/1572864\\n[TRACE runtime::revive::strace] call_data_size() = Ok(0) gas_consumed: Weight { ref_time: 985209, proof_size: 0 }\\n[TRACE runtime::revive::strace] value_transferred(out_ptr: 4294836096) = Ok(()) gas_consumed: Weight { ref_time: 2937634, proof_size: 0 }\\n[TRACE runtime::revive::strace] call_data_copy(out_ptr: 131216, out_len: 0, offset: 0) = Ok(()) gas_consumed: Weight { ref_time: 4084483, proof_size: 0 }\\n[TRACE runtime::revive::strace] seal_return(flags: 0, data_ptr: 131216, data_len: 0) = Err(TrapReason::Return(ReturnData { flags: 0, data: [] })) gas_consumed: Weight { ref_time: 5510615, proof_size: 0 }\\n[TRACE runtime::revive] frame finished with: Ok(ExecReturnValue { flags: (empty), data: [] })\\n[TRACE runtime::revive::strace] call_data_size() = Ok(0) gas_consumed: Weight { ref_time: 985209, proof_size: 0 }\\n[TRACE runtime::revive::strace] seal_return(flags: 1, data_ptr: 131088, data_len: 0) = Err(TrapReason::Return(ReturnData { flags: 1, data: [] })) gas_consumed: Weight { ref_time: 2456669, proof_size: 0 }\\n[TRACE runtime::revive] frame finished with: Ok(ExecReturnValue { flags: REVERT, data: [] })","breadcrumbs":"revive-runner sandbox » Example","id":"57","title":"Example"},"58":{"body":"This chapter covers internal aspects of the compiler and helps contributors getting started with the revive codebase.","breadcrumbs":"Developer Guide » Developer guide","id":"58","title":"Developer guide"},"59":{"body":"The revive compiler is an open source software project and we gladly accept quality contributions from anyone!","breadcrumbs":"Developer Guide » Contributor guide » Contributor guide","id":"59","title":"Contributor guide"},"6":{"body":"Building Solidity contracts for PolkaVM requires installing the following two compilers: solc: The Ethereum Solidity reference compiler implementation. resolc: The revive Solidity compiler YUL frontend and PolkaVM code generator.","breadcrumbs":"resolc user guide » Installation » Installation","id":"6","title":"Installation"},"60":{"body":"A quick reference on how to build the Solidity compiler is maintained in the project’s README.md.","breadcrumbs":"Developer Guide » Contributor guide » Getting started","id":"60","title":"Getting started"},"61":{"body":"The Makefile comprehensively encapsulates all development aspects of this codebase. It is kept concise and readable. Please read and use it! You’ll learn for example: How to build and install a resolc development version. How to run tests and benchmarks. How to cross-compile resolc. As a general rule-of-thumb: If make test runs fine locally, chances for green CI pipelines are good.","breadcrumbs":"Developer Guide » Contributor guide » Using the Makefile","id":"61","title":"Using the Makefile"},"62":{"body":"For the most parts, revive is a rather standard Rust workspace codebase. There are some non-Rust dependencies, which sometimes complicates things a little bit. The crates/ dir All Rust crates live under the crates/ directory. The workspace automatically considers any crate found therein. If you need to add a new create, please implement it there. Compiler library crates should be named with the revive- prefix. The crate location doesn’t need the prefix. Dependencies Dependencies should be added as workspace dependencies. Try to avoid pinning dependencies whenever possible. If possible, add dev dependencies as dev-dependencies only. Please do always include the Cargo.lock dependency lock file with your PR. Please don’t run cargo update together with other changes (it is preferred to update the lock file in a dedicated dependency update PR).","breadcrumbs":"Developer Guide » Contributor guide » Codebase organization","id":"62","title":"Codebase organization"},"63":{"body":"Changes must be submitted via a pull request (PR) to the github upstream repository. Ensure that your branch passes make test locally when submitting a pull request. A PR must not be merged until CI fully passes. Exceptions can be made (for example to fix CI issues itself). No force pushes to the main branch and open PR branches. Maintainers can request changes or deny contributions at their own discretion.","breadcrumbs":"Developer Guide » Contributor guide » Contribution rules","id":"63","title":"Contribution rules"},"64":{"body":"We require the official Rust formatter and clippy linter. In addition to that, please also consider the following best-effort aspects: Avoid magic numbers and strings. Instead, add them as module constants. Avoid abbreviated variable and function names. Always provide meaningful and readable symbols. Don’t write macros and don’t use third party macros for things that can easily be expressed in few lines of code or outlined into functions. Avoid import aliasing. Please use the parent or fully qualified path for conflicting symbols. Any inline comments must provide additional semantic meaning, explain counter-intuitive behavior or highlight non-obvious design decisions. In other words, try to make the code expressive enough to a degree it doesn’t need comments expressing the same thing again in the English language. Delete such comments if your AI assistant generated them. Public items must have a meaningful doc comment. Provide meaningful panic messages to .expect() or just use .unwrap().","breadcrumbs":"Developer Guide » Contributor guide » Style guide","id":"64","title":"Style guide"},"65":{"body":"Contributors may use whatever AI assistance tools they wish to whatever degree they wish in the process of creating their contribution, given they acknowledge the following: Project maintainers may reject any contribution (or portions of it) if the contribution shows signs of problematic involvement of generative AI. Judgement of “problematic involvement” lies at the sole discretion of project maintainers. No proof (whether a contribution was in fact AI generated or not) is required. Rationale: No one enjoys reading soulless and uncanny LLM slop. Please review and fix any AI slop yourself prior to submitting a PR. A Solidity compiler is security sensitive software. Even miniscule mistakes can ultimately lead to loss of funds. AI models are inherently stochastic. They regurarly fail to capture important nuances or produce straight hallucinations. Code that was “blindly” generated has no home here. revive is a large codebase. Generative AI assistants may not have enough “context window” to sufficiently capture correctness, consistency and style aspects of the codebase. We’d like to keep this codebase maintainable by humans for the forseeable future.","breadcrumbs":"Developer Guide » Contributor guide » AI policy","id":"65","title":"AI policy"},"66":{"body":"revive relies on solc, the Ethereum Solidity compiler, as the Solidity frontend to process smart contracts written in Solidity. LLVM, a popular and powerful compiler framework, is used as the compiler backend and does the heavy lifting in terms of optimizitations and RISC-V code generation. revive mainly takes care of lowering the Yul intermediate representation (IR) produced by solc to LLVM IR. This approach provides a good balance between maintaining a high level of Ethereum compatibility, good contract performance and feasible engineering efforts.","breadcrumbs":"Developer Guide » Compiler architecture » Compiler architecture and internals","id":"66","title":"Compiler architecture and internals"},"67":{"body":"resolc is the overarching compiler driver library and binary. When compiling a Solidity source file with resolc, the following steps happen under the hood: solc is used to lower the Solidity source code into YUL intermediate representation. revive lowers the YUL IR into LLVM IR. LLVM optimizes the code and emits a RISC-V ELF shared object (through LLD). The PolkaVM linker finally links the ELF shared object into a PolkaVM blob. This compilation process can be visualized as follows:","breadcrumbs":"Developer Guide » Compiler architecture » resolc","id":"67","title":"resolc"},"68":{"body":"Because on-chain contract code is identified via its code blob hash, it is crucial to maintain reproducible contract builds. A given compiler version must reproduce the contract build exactly on every target platform resolc supports via the official binary releases. To ensure this, we employ the following measures: The code generation must be fully deterministic. For example iterating over standard HashMap invalidates this due to its internal state, making it an invalid operation in revive. To circumvent that, a BTreeMap can be used instead. We release fully statically linked resolc binaries. This prevents dynamic linking of potentially differentiating libraries. The only non-bundled dependency is the solc compiler. This is considered fine because the same properties apply to solc.","breadcrumbs":"Developer Guide » Compiler architecture » Reproducible contract builds","id":"68","title":"Reproducible contract builds"},"69":{"body":"The main compiler logic is implemented in the revive-yul and revive-llvm-context crates. The Yul library implements a lexer and parser and lowers the resulting tree into LLVM IR. It does so by emitting LL using the LLVM builder and our own revive-llvm-context compiler context crate. The revive LLVM context crate encapsulates code generation logic (decoupled from the parser). The Yul library also implements a simple visitor interface (see visitor.rs). If you want to work with the AST, it is strongly recommended to implement visitors. The LLVM code generation is implemented using a dedicated trait for historical reasons only.","breadcrumbs":"Developer Guide » Compiler architecture » The revive compiler libraries","id":"69","title":"The revive compiler libraries"},"7":{"body":"resolc is supported an all major operating systems and installation is straightforward.\\nPlease find our binary releases for the following platforms: Linux (MUSL) MacOS (universal) Windows Wasm via emscripten","breadcrumbs":"resolc user guide » Installation » resolc binary releases","id":"7","title":"resolc binary releases"},"70":{"body":"PVM doesn’t offer a similar API. Hence the emitted contract code emulates the linear EVM heap memory using a static byte buffer. Data inside this byte buffer is kept big endian for EVM compatibility reasons (unaligned access is allowed and makes optimizing this non-trivial). Unlike with the EVM, where heap memory usage is gas metered, our heap size is static (the size is user controllable via a setting flag). The compiler emits bound checks to prevent overflows.","breadcrumbs":"Developer Guide » Compiler architecture » EVM heap memory","id":"70","title":"EVM heap memory"},"71":{"body":"LLVM is a special non Rust dependency. We interface its builder interface via the inkwell wrapper crate. We use upstream LLVM, but release and use our custom builds. We require the compiler builtins specifically built for the PVM rv64emacb target and always leave assertions on. Furthermore, we need cross builds because resolc itself targets emscripten and musl. The revive-llvm-builer functions as a cross-platform build script and is used to build and release the LLVM dependency. We also maintain the lld-sys crate for interfacing with LLD. The LLVM linker is used during the compilation process, but we don’t want to distribute another binary.","breadcrumbs":"Developer Guide » Compiler architecture » The LLVM dependency","id":"71","title":"The LLVM dependency"},"72":{"body":"At the moment, no significant custom optimizations are implemented. Thus, we are missing some optimization opportunities that neither solc nor LLVM can realize (due to their lack of domain specific knowledge about the semantics of our target environment). Furthermore, solc optimizes for EVM gas and a target machine orthogonal to our target (BE 256-bit stack machine EVM vs. 64-bit LE RISC architecture PVM). We have started working on an additional IR layer between Yul and LLVM to capture missed optimization opportunities, though.","breadcrumbs":"Developer Guide » Compiler architecture » Custom optimizations","id":"72","title":"Custom optimizations"},"73":{"body":"The revive compiler targets PolkaVM (PVM) via pallet-revive on Polkadot.","breadcrumbs":"Developer Guide » PVM and the pallet-revive runtime target » PVM and the pallet-revive runtime target","id":"73","title":"PVM and the pallet-revive runtime target"},"74":{"body":"The exact target CPU configuration can be found here. Note The PVM linker requires fully relocatable ELF objects.","breadcrumbs":"Developer Guide » PVM and the pallet-revive runtime target » Target CPU configuration","id":"74","title":"Target CPU configuration"},"75":{"body":"PVM is a RISC-V based VM designed to overcome the flaws of WebAssebmly (Wasm). Wasm was believed to be a more efficient successor to the rather slow EVM. However, Wasm is far from an ideal target for smart contracts as some of its design decisions are unfavorable for short-lived workloads. The main problem is on-chain Wasm bytecode compilation or interpretation overhead. Prior benchmarks consistently ignoring this overhead seeded the blockchain industry with flawed assumptions: Only when ignoring the startup overhead Wasm is much faster than the slow computing EVM. In practice however, gains are nullified entirely and Wasm loses completely even against very slow VMs like the EVM. Executing Wasm contracts is in fact so inefficient that typical contract workloads are orders of magnitude more expensive than the equivalent EVM variant. On the other hand, since RISC-V is similar to CPUs found in validator hardware (x86 and ARM), bytecode translation mostly boils down to a linear mapping from one instruction to another. The embedded ISA specification reduces the number of general purpose registers, in turn removing the need for expensive register allocation. This guarantees single-pass O(n) JIT compilation of contract bytecode. The close proximity of PVM bytecode with actual validator CPU bytecode effectively allows to move all expensive compilation workload off-chain. Benchmarks ( 1, 2) show that with the PVM JIT, sandboxed PVM code executes at around half the speed of native code, which falls into the same ballpark of the state-of-the-art wasmtime Wasm implementation (while EVM sits somewhere around 1/10 to less than 1/100 of native speed). However, the PVM JIT compiler only uses a fraction of the time wasmtime requires to compile the code. Note The PVM JIT isn’t available yet in pallet-revive. At the time of writing, the contract code is interpreted, which is orders of magnitude slower than the JIT.","breadcrumbs":"Developer Guide » PVM and the pallet-revive runtime target » Why PVM","id":"75","title":"Why PVM"},"76":{"body":"The revive compiler targets the pallet-revive runtime environment. pallet-revive exposes a syscall like interface for contract interactions with the host environment. This is provided by the revive-runtime-api library. After the initial launch on the Polkadot Asset Hub blockchain, the runtime API is considered stable and backwards compatible indefinitively.","breadcrumbs":"Developer Guide » PVM and the pallet-revive runtime target » Host environment: pallet-revive","id":"76","title":"Host environment: pallet-revive"},"77":{"body":"Contributors are encouraged to implement some appropriate unit and integration tests together with any bug fixes or new feature implementations. However, when it comes to testing the code generation logic, our testing strategy goes way beyond simple unit and integration tests. This chapter explains how the revive compiler implementation is tested for correctness and how we define correctness. Tip Running the integration tests require the evm tool from go-ethereum in your $PATH. Either install it using your package manager or to build it from source: git clone https://github.com/ethereum/go-ethereum/\\ncd go-ethereum\\nmake all\\nexport PATH=/path/to/go-ethereum/build/bin/:$PATH","breadcrumbs":"Developer Guide » Testing strategy » Testing strategy","id":"77","title":"Testing strategy"},"78":{"body":"As a Solidity compiler, we aim to preserve contract code semantics as close as possible to Solidity compiled to EVM with the solc reference implementation. As highlighted in the user guide, due to the underlying target difference, this isn’t always possible. However, wherever it is possible, we follow the philosophy of bug compatibility with the Ethereum contracts stack.","breadcrumbs":"Developer Guide » Testing strategy » Bug compatibility with Ethereum Solidity","id":"78","title":"Bug compatibility with Ethereum Solidity"},"79":{"body":"A high level of bug compatibility with Ethereum is ensured through differential testing with the Ethereum solc and EVM contracts stack. The revive-integration library is the central integration test utility, providing a set of Solidity integration test cases. Further, it implements differential tests against the reference implementation by combining the revive-runner sandbox, the go-ethereum EVM tool and the revive-differential. The revive-runner library provides a declarative test specification format. This vastly simplifies writing differential test cases and removes a lot of room for errors in test logic. Example: { \\"differential\\": true, \\"actions\\": [ { \\"Instantiate\\": { \\"code\\": { \\"Solidity\\": { \\"contract\\": \\"Bitwise\\" } } } }, { \\"Call\\": { \\"dest\\": { \\"Instantiated\\": 0 }, \\"data\\": \\"3fa4f245\\" } } ]\\n} Above example instantiates the Bitwise contract and calls it with some defined calldata. The revive-runner library implements a helper wrapper to execute test specs on the go-ethereum standalone evm tool. This allows the revive-runner to execute specs against the EVM and the pallet-revive runtime. Key to differential testing is setting \\"differential\\": true, resulting in the following: The Bitwise contract is compiled to EVM and PVM code. The runner executes the defined actions on the EVM and collects all state changes (storage, balance) and execution results. The runner executes each action on the PVM. Observed state changes after each step as well as the final execution result is asserted to match the EVM counterparts exactly. Note how we never defined any expected outcome manually. Instead, we simply observe and collect the data defining the “correct” outcome. Differential testing in combination with declarative test specifications proved to be simple, yet very effective, in ensuring expected Ethereum Solidity semantics on pallet-revive.","breadcrumbs":"Developer Guide » Testing strategy » Differential integration tests","id":"79","title":"Differential integration tests"},"8":{"body":"resolc uses solc during the compilation process, please refer to the Ethereum Solidity documentation for installation instructions.","breadcrumbs":"resolc user guide » Installation » Installing the solc dependency","id":"8","title":"Installing the solc dependency"},"80":{"body":"A lot of nuanced bugs caused by tiny implementation details inside the revive compiler and the pallet-revive runtime could be identified and eliminated early on thanks to the differential testing strategy. Thus, we decided to take this approach further and created a comprehensive test runner and a large suite of more complex test cases. The Revive Differential Tests follow the exact same strategy but implement a much more powerful test spec format, spec runner and reports. This allows differentially testing much more complex test cases (for example testing Uniswap pair creations and swaps), executed via transactions sent to actual blockchain nodes.","breadcrumbs":"Developer Guide » Testing strategy » The differential testing utility","id":"80","title":"The differential testing utility"},"81":{"body":"We cross-compile the resolc.js frontend executable to Wasm for running it in a Node.js or browser environment. The musl target is used to obtain statically linked ELF binaries for Linux.","breadcrumbs":"Developer Guide » Cross compilation » Cross compilation","id":"81","title":"Cross compilation"},"82":{"body":"The REVIVE_LLVM_TARGET_PREFIX environment variable is used to control the target environment LLVM dependency. This requires a compatible LLVM build, obtainable via the revive-llvm build script. Example: # Build the host LLVM dependency with PolkaVM target support\\nmake install-llvm\\nexport LLVM_SYS_181_PREFIX=${PWD}/target-llvm/gnu/target-final # Build the target LLVM dependency with PolkaVM target support\\nrevive-llvm emsdk\\nsource emsdk/emsdk_env.sh\\nrevive-llvm --target-env emscripten build --llvm-projects lld\\nexport REVIVE_LLVM_TARGET_PREFIX=${PWD}/target-llvm/emscripten/target-final # Build the resolc frontend executable\\nmake install-wasm\\nmake test-wasm","breadcrumbs":"Developer Guide » Cross compilation » Wasm via emscripten","id":"82","title":"Wasm via emscripten"},"83":{"body":"rust-musl-cross is a straightforward way to cross compile Rust to musl. The Dockerfile is an executable example of how to do that.","breadcrumbs":"Developer Guide » Cross compilation » musl libc","id":"83","title":"musl libc"},"84":{"body":"","breadcrumbs":"FAQ » FAQ","id":"84","title":"FAQ"},"85":{"body":"We neither do nor don’t support any EVM version. We support Solidity versions, starting from solc version 0.8.0 onwards.","breadcrumbs":"FAQ » What EVM version do you support?","id":"85","title":"What EVM version do you support?"},"86":{"body":"Yes, almost all inline assembly features are supported ( see the differences in Yul translation chapter).","breadcrumbs":"FAQ » Is inline assembly supported","id":"86","title":"Is inline assembly supported"},"87":{"body":"See above, the same applies.","breadcrumbs":"FAQ » Do you support opcode XY?","id":"87","title":"Do you support opcode XY?"},"88":{"body":"We generally recommend to always use the latest supported version to profit from latest bugfixes, features and performance improvements. Find out about the latest supported version by running resolc --supported-solc-versions or checking here.","breadcrumbs":"FAQ » In what Solidity version should I write my dApp?","id":"88","title":"In what Solidity version should I write my dApp?"},"89":{"body":"The 24kb code size restriction only exist for the EVM. Our limit is currently around 1mb and may increase further in the future.","breadcrumbs":"FAQ » Tool XY says the contract size is larger than 24kb and will fail to deploy?","id":"89","title":"Tool XY says the contract size is larger than 24kb and will fail to deploy?"},"9":{"body":"We distribute the revive compiler as node.js module.","breadcrumbs":"resolc user guide » Installation » revive NPM package","id":"9","title":"revive NPM package"},"90":{"body":"No. resolc aims to work similarly to solc, but it’s not considered a drop-in replacement.","breadcrumbs":"FAQ » Is resolc a drop-in replacement for solc?","id":"90","title":"Is resolc a drop-in replacement for solc?"},"91":{"body":"The revive compiler speeds up Solidity contracts significantly. revive provides a decisive edge over other contract platforms. Notably, the compiler eliminates the need of rewriting Solidity dApps in Rust or even as single dApp parachains for scaling reasons. Retaining as high compatibility with Ethereum Solidity as possible keeps entry barriers low. We believe in Dr. Gavin Wood’s ĐApps: What Web 3.0 Looks Like manifesto and the ecosystem of the Solidity programming language. Our motivation lies in the realization that for a true web3 revolution, significant scaling efforts, like the ones provided by the PVM and this project, are necessary to unfold.","breadcrumbs":"Roadmap and Vision » Vision and Roadmap","id":"91","title":"Vision and Roadmap"},"92":{"body":"The first major release, resolc v1.0.0, emits functional PVM code from given Solidity sources. It relies on solc and LLVM for optimizations. The main priority of this release was delivering a mostly feature complete and safe Solidity v0.8.0 compiler. Focus for the second major release is on the custom optimization pipeline, which aims to significantly improve emitted code blob sizes. The below roadmap gives a rough overview of the project’s development timeline.","breadcrumbs":"Roadmap and Vision » Roadmap","id":"92","title":"Roadmap"}},"length":93,"save":true},"fields":["title","body","breadcrumbs"],"index":{"body":{"root":{"0":{".":{"8":{".":{"0":{"df":1,"docs":{"85":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":5,"docs":{"12":{"tf":1.0},"41":{"tf":1.0},"51":{"tf":1.4142135623730951},"57":{"tf":3.4641016151377544},"79":{"tf":1.0}}},"1":{".":{"2":{"df":1,"docs":{"18":{"tf":1.0}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"s":{"df":1,"docs":{"14":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"/":{"1":{"0":{"0":{"df":1,"docs":{"75":{"tf":1.0}}},"df":1,"docs":{"75":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"2":{"8":{"df":0,"docs":{},"k":{"b":{"df":3,"docs":{"40":{"tf":1.4142135623730951},"41":{"tf":1.0},"46":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}},"3":{"1":{"0":{"7":{"2":{"df":2,"docs":{"13":{"tf":1.0},"14":{"tf":1.0}}},"df":0,"docs":{}},"8":{"8":{"df":1,"docs":{"57":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"2":{"1":{"6":{"df":1,"docs":{"57":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":5,"docs":{"12":{"tf":1.0},"39":{"tf":1.0},"51":{"tf":1.4142135623730951},"57":{"tf":1.4142135623730951},"75":{"tf":1.0}},"m":{"b":{"df":1,"docs":{"89":{"tf":1.0}}},"df":0,"docs":{}}},"2":{".":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":1,"docs":{"14":{"tf":1.0}}}}}},"4":{"5":{"6":{"6":{"6":{"9":{"df":1,"docs":{"57":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{},"k":{"b":{"df":1,"docs":{"89":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"5":{"0":{"0":{"0":{"0":{"0":{"0":{"0":{"0":{"0":{"0":{"0":{"0":{"0":{"0":{"df":1,"docs":{"47":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"6":{"df":1,"docs":{"72":{"tf":1.0}}},"df":0,"docs":{}},"9":{"3":{"7":{"6":{"3":{"4":{"df":1,"docs":{"57":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"^":{"3":{"2":{"df":1,"docs":{"39":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":3,"docs":{"12":{"tf":1.0},"32":{"tf":1.0},"75":{"tf":1.0}}},"3":{".":{"0":{"df":1,"docs":{"91":{"tf":1.0}}},"df":0,"docs":{}},"2":{"df":2,"docs":{"39":{"tf":1.0},"45":{"tf":1.0}}},"df":2,"docs":{"12":{"tf":1.0},"18":{"tf":1.4142135623730951}},"f":{"a":{"4":{"df":0,"docs":{},"f":{"2":{"4":{"5":{"df":1,"docs":{"79":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}},"4":{"0":{"8":{"4":{"4":{"8":{"3":{"df":1,"docs":{"57":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"2":{"9":{"4":{"8":{"3":{"6":{"0":{"9":{"6":{"df":1,"docs":{"57":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"5":{"5":{"1":{"0":{"6":{"1":{"5":{"df":1,"docs":{"57":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"6":{"3":{"/":{"6":{"4":{"df":2,"docs":{"0":{"tf":1.0},"37":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"4":{"df":1,"docs":{"72":{"tf":1.0}}},"df":0,"docs":{}},"9":{"8":{"5":{"2":{"0":{"9":{"df":1,"docs":{"57":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"d":{"df":1,"docs":{"51":{"tf":1.7320508075688772}}},"df":0,"docs":{}}}}}}}}}},"df":0,"docs":{}}}},"a":{"b":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"52":{"tf":1.0}}}}},"df":0,"docs":{}}},"b":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"df":1,"docs":{"64":{"tf":1.0}}}}}}},"df":0,"docs":{},"i":{"df":1,"docs":{"33":{"tf":1.4142135623730951}}},"o":{"df":0,"docs":{},"v":{"df":3,"docs":{"39":{"tf":1.0},"79":{"tf":1.0},"87":{"tf":1.0}}}}},"c":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":1,"docs":{"59":{"tf":1.0}}}},"s":{"df":0,"docs":{},"s":{"df":2,"docs":{"40":{"tf":1.0},"70":{"tf":1.0}}}}}},"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":1,"docs":{"20":{"tf":1.0}}}}}},"k":{"df":0,"docs":{},"n":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"d":{"df":0,"docs":{},"g":{"df":1,"docs":{"65":{"tf":1.0}}}},"df":0,"docs":{}}}}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"79":{"tf":1.7320508075688772}}}},"v":{"df":2,"docs":{"18":{"tf":1.0},"23":{"tf":1.0}}}},"u":{"a":{"df":0,"docs":{},"l":{"df":4,"docs":{"18":{"tf":1.0},"35":{"tf":1.0},"75":{"tf":1.0},"80":{"tf":1.0}}}},"df":0,"docs":{}}}},"d":{"d":{"df":2,"docs":{"62":{"tf":1.4142135623730951},"64":{"tf":1.0}},"i":{"df":0,"docs":{},"t":{"df":4,"docs":{"24":{"tf":1.0},"4":{"tf":1.0},"64":{"tf":1.4142135623730951},"72":{"tf":1.0}},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"33":{"tf":1.0}}}}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{".":{"c":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"o":{"d":{"df":1,"docs":{"38":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":1,"docs":{"18":{"tf":1.4142135623730951}}}}}}},"df":2,"docs":{"33":{"tf":1.4142135623730951},"62":{"tf":1.0}},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":1,"docs":{"52":{"tf":1.0}}}}},"v":{"a":{"df":0,"docs":{},"n":{"c":{"df":1,"docs":{"12":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"37":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{},"g":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"64":{"tf":1.0}},"s":{"df":0,"docs":{},"t":{"df":3,"docs":{"52":{"tf":1.0},"75":{"tf":1.0},"79":{"tf":1.4142135623730951}}}}}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"12":{"tf":1.4142135623730951}}}}}}}},"i":{"df":3,"docs":{"52":{"tf":1.4142135623730951},"64":{"tf":1.0},"65":{"tf":2.6457513110645907}},"m":{"df":4,"docs":{"11":{"tf":1.0},"78":{"tf":1.0},"90":{"tf":1.0},"92":{"tf":1.0}}}},"l":{"df":0,"docs":{},"g":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"m":{"df":1,"docs":{"52":{"tf":1.0}}}}}}}}},"i":{"a":{"df":0,"docs":{},"s":{"df":1,"docs":{"64":{"tf":1.0}}}},"df":0,"docs":{}},"l":{"df":0,"docs":{},"o":{"c":{"df":1,"docs":{"75":{"tf":1.0}}},"df":0,"docs":{},"w":{"df":7,"docs":{"26":{"tf":1.0},"27":{"tf":1.4142135623730951},"30":{"tf":1.0},"70":{"tf":1.0},"75":{"tf":1.0},"79":{"tf":1.0},"80":{"tf":1.0}}}}},"w":{"a":{"df":0,"docs":{},"y":{"df":10,"docs":{"18":{"tf":1.0},"39":{"tf":1.0},"41":{"tf":1.0},"43":{"tf":1.0},"50":{"tf":1.0},"62":{"tf":1.0},"64":{"tf":1.0},"71":{"tf":1.0},"78":{"tf":1.0},"88":{"tf":1.0}}}},"df":0,"docs":{}}},"m":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":4,"docs":{"0":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"37":{"tf":1.0}}}}}}},"n":{"df":0,"docs":{},"n":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"c":{"df":1,"docs":{"22":{"tf":1.0}}},"df":0,"docs":{}}}}},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":2,"docs":{"71":{"tf":1.0},"75":{"tf":1.0}}}}},"y":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"59":{"tf":1.0}}}}}},"p":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":1,"docs":{"43":{"tf":1.0}}}}},"df":0,"docs":{},"i":{"df":2,"docs":{"70":{"tf":1.0},"76":{"tf":1.4142135623730951}}},"p":{"df":1,"docs":{"91":{"tf":1.0}},"e":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"18":{"tf":1.0}}},"df":0,"docs":{}}},"l":{"df":0,"docs":{},"i":{"c":{"df":2,"docs":{"5":{"tf":1.0},"52":{"tf":1.4142135623730951}}},"df":7,"docs":{"12":{"tf":1.4142135623730951},"27":{"tf":1.0},"37":{"tf":1.0},"40":{"tf":1.0},"52":{"tf":1.0},"68":{"tf":1.0},"87":{"tf":1.0}}}},"r":{"df":0,"docs":{},"o":{"a":{"c":{"df":0,"docs":{},"h":{"df":2,"docs":{"66":{"tf":1.0},"80":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"77":{"tf":1.0}}}}}}}}},"r":{"b":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"30":{"tf":1.0}}}}},"df":0,"docs":{}}}}},"c":{"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":3,"docs":{"43":{"tf":1.0},"66":{"tf":1.0},"72":{"tf":1.0}}}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"u":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":4,"docs":{"30":{"tf":1.0},"39":{"tf":1.0},"43":{"tf":1.7320508075688772},"56":{"tf":1.0}}}}}}}},"m":{"df":1,"docs":{"75":{"tf":1.0}}},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"d":{"df":3,"docs":{"52":{"tf":1.0},"75":{"tf":1.4142135623730951},"89":{"tf":1.0}}},"df":0,"docs":{}}}},"t":{"df":1,"docs":{"75":{"tf":1.0}},"i":{"df":0,"docs":{},"f":{"a":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"16":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"s":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":4,"docs":{"58":{"tf":1.0},"61":{"tf":1.0},"64":{"tf":1.0},"65":{"tf":1.0}}}},"df":0,"docs":{}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"b":{"df":0,"docs":{},"l":{"df":5,"docs":{"16":{"tf":1.0},"39":{"tf":1.0},"4":{"tf":1.0},"43":{"tf":1.7320508075688772},"86":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"t":{"df":2,"docs":{"71":{"tf":1.0},"79":{"tf":1.0}}}},"t":{"df":1,"docs":{"76":{"tf":1.0}}}},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":2,"docs":{"64":{"tf":1.0},"65":{"tf":1.4142135623730951}}}}},"u":{"df":0,"docs":{},"m":{"df":2,"docs":{"43":{"tf":1.0},"50":{"tf":1.0}},"p":{"df":0,"docs":{},"t":{"df":1,"docs":{"75":{"tf":1.0}}}}}}},"t":{"df":2,"docs":{"33":{"tf":1.7320508075688772},"69":{"tf":1.0}}}},"u":{"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"c":{"df":1,"docs":{"1":{"tf":1.0}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"28":{"tf":1.0}}}}}}},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"39":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"t":{"df":3,"docs":{"33":{"tf":1.4142135623730951},"56":{"tf":1.4142135623730951},"62":{"tf":1.0}}}},"df":0,"docs":{}}}}},"v":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":5,"docs":{"14":{"tf":1.0},"21":{"tf":1.0},"22":{"tf":1.0},"50":{"tf":1.0},"75":{"tf":1.0}}}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"i":{"d":{"df":3,"docs":{"56":{"tf":1.0},"62":{"tf":1.0},"64":{"tf":1.7320508075688772}}},"df":0,"docs":{}}}},"w":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"36":{"tf":1.0}}}},"df":0,"docs":{}}},"b":{"a":{"c":{"df":0,"docs":{},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"d":{"df":2,"docs":{"12":{"tf":1.0},"66":{"tf":1.0}}},"df":0,"docs":{}}},"w":{"a":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"76":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"n":{"c":{"df":2,"docs":{"66":{"tf":1.0},"79":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"k":{"df":1,"docs":{"75":{"tf":1.0}}}}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"91":{"tf":1.0}}}}}}},"s":{"df":0,"docs":{},"e":{"df":5,"docs":{"17":{"tf":1.0},"50":{"tf":1.0},"51":{"tf":1.0},"52":{"tf":1.0},"75":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"=":{"1":{"0":{"3":{"0":{"6":{"3":{"/":{"1":{"5":{"7":{"2":{"8":{"6":{"4":{"df":1,"docs":{"57":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"i":{"c":{"df":1,"docs":{"12":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":2,"docs":{"51":{"tf":1.0},"56":{"tf":1.0}}}}},"h":{"a":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":2,"docs":{"50":{"tf":1.0},"64":{"tf":1.0}}}}}}},"df":0,"docs":{}},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":2,"docs":{"75":{"tf":1.0},"91":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"w":{"df":3,"docs":{"18":{"tf":1.0},"39":{"tf":1.0},"92":{"tf":1.0}}}}},"n":{"c":{"df":0,"docs":{},"h":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"k":{"df":2,"docs":{"61":{"tf":1.0},"75":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"52":{"tf":1.0}}}}}}},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"64":{"tf":1.0}}}},"t":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"52":{"tf":1.0}}}}},"w":{"df":0,"docs":{},"e":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":5,"docs":{"12":{"tf":1.0},"35":{"tf":1.0},"50":{"tf":1.0},"66":{"tf":1.0},"72":{"tf":1.0}}}}}}},"y":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"d":{"df":2,"docs":{"52":{"tf":1.0},"77":{"tf":1.0}}},"df":0,"docs":{}}}}},"i":{"df":0,"docs":{},"g":{"df":1,"docs":{"70":{"tf":1.0}}},"n":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":7,"docs":{"5":{"tf":1.0},"53":{"tf":1.0},"67":{"tf":1.0},"68":{"tf":1.4142135623730951},"7":{"tf":1.4142135623730951},"71":{"tf":1.0},"81":{"tf":1.0}}}}},"df":1,"docs":{"19":{"tf":1.0}}},"t":{"df":3,"docs":{"39":{"tf":1.0},"62":{"tf":1.0},"72":{"tf":1.4142135623730951}},"w":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":1,"docs":{"79":{"tf":1.7320508075688772}}}}}}},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"65":{"tf":1.0}}}}},"df":0,"docs":{}}},"o":{"b":{"b":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":1,"docs":{"49":{"tf":1.0}}}}}}},"df":0,"docs":{}},"df":6,"docs":{"18":{"tf":1.7320508075688772},"35":{"tf":1.4142135623730951},"49":{"tf":1.0},"67":{"tf":1.0},"68":{"tf":1.0},"92":{"tf":1.0}},"h":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"df":1,"docs":{"49":{"tf":1.0}}}}},"df":0,"docs":{}}},"c":{"df":0,"docs":{},"k":{"c":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":5,"docs":{"52":{"tf":1.0},"53":{"tf":1.4142135623730951},"75":{"tf":1.0},"76":{"tf":1.0},"80":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":1,"docs":{"43":{"tf":1.7320508075688772}}}},"df":0,"docs":{}}},"o":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"75":{"tf":1.0}}}},"o":{"df":0,"docs":{},"k":{"df":2,"docs":{"0":{"tf":1.0},"3":{"tf":1.4142135623730951}}},"l":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"n":{"df":1,"docs":{"26":{"tf":1.0}}}},"df":0,"docs":{}}}},"t":{"df":0,"docs":{},"h":{"df":2,"docs":{"18":{"tf":1.0},"35":{"tf":1.0}}}},"u":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"70":{"tf":1.0}}},"df":0,"docs":{}}}},"r":{"a":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"h":{"df":1,"docs":{"63":{"tf":1.7320508075688772}}}},"df":0,"docs":{}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"81":{"tf":1.0}}}}}}}},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"68":{"tf":1.0}}}},"df":0,"docs":{}}}}}},"u":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":5,"docs":{"14":{"tf":1.0},"39":{"tf":1.4142135623730951},"40":{"tf":1.4142135623730951},"43":{"tf":1.4142135623730951},"70":{"tf":1.4142135623730951}}}}}},"g":{"df":5,"docs":{"23":{"tf":1.0},"77":{"tf":1.0},"78":{"tf":1.4142135623730951},"79":{"tf":1.0},"80":{"tf":1.0}},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"x":{"df":1,"docs":{"88":{"tf":1.0}}}}}},"i":{"d":{"df":0,"docs":{},"l":{"df":1,"docs":{"10":{"tf":1.0}}}},"df":0,"docs":{},"l":{"d":{"df":8,"docs":{"10":{"tf":1.0},"6":{"tf":1.0},"60":{"tf":1.0},"61":{"tf":1.0},"68":{"tf":1.7320508075688772},"71":{"tf":2.0},"77":{"tf":1.0},"82":{"tf":2.449489742783178}},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"69":{"tf":1.0},"71":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"71":{"tf":1.0}}}},"t":{"df":1,"docs":{"71":{"tf":1.0}},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"71":{"tf":1.0}}}}}}},"n":{"d":{"df":0,"docs":{},"l":{"df":1,"docs":{"68":{"tf":1.0}}}},"df":0,"docs":{}},"s":{"df":0,"docs":{},"i":{"df":1,"docs":{"52":{"tf":1.0}}}}},"y":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"o":{"d":{"df":4,"docs":{"18":{"tf":1.0},"33":{"tf":1.4142135623730951},"38":{"tf":1.0},"75":{"tf":2.23606797749979}}},"df":0,"docs":{}}},"df":2,"docs":{"40":{"tf":1.0},"70":{"tf":1.4142135623730951}}}}}},"c":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"_":{"d":{"a":{"df":0,"docs":{},"t":{"a":{"_":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"y":{"(":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":1,"docs":{"57":{"tf":1.0}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"s":{"df":1,"docs":{"57":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"18":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"d":{"a":{"df":0,"docs":{},"t":{"a":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":1,"docs":{"41":{"tf":1.0}}}}}},"df":2,"docs":{"41":{"tf":1.0},"79":{"tf":1.0}},"l":{"df":0,"docs":{},"o":{"a":{"d":{"df":1,"docs":{"41":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":6,"docs":{"0":{"tf":1.0},"18":{"tf":1.0},"35":{"tf":1.0},"37":{"tf":1.0},"56":{"tf":1.0},"79":{"tf":1.4142135623730951}}}},"n":{"df":0,"docs":{},"’":{"df":0,"docs":{},"t":{"df":1,"docs":{"52":{"tf":1.0}}}}},"p":{"df":1,"docs":{"40":{"tf":1.0}},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":2,"docs":{"65":{"tf":1.4142135623730951},"72":{"tf":1.0}}}}}},"r":{"df":0,"docs":{},"e":{"df":2,"docs":{"18":{"tf":1.0},"66":{"tf":1.0}},"f":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"0":{"tf":1.0}}}}}}}},"g":{"df":0,"docs":{},"o":{".":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{"df":1,"docs":{"62":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":1,"docs":{"62":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"e":{"df":5,"docs":{"18":{"tf":2.0},"48":{"tf":1.0},"49":{"tf":1.0},"79":{"tf":1.4142135623730951},"80":{"tf":1.4142135623730951}}}},"u":{"df":0,"docs":{},"s":{"df":1,"docs":{"80":{"tf":1.0}}}},"v":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"40":{"tf":1.0}}}},"df":0,"docs":{}}}},"d":{"df":1,"docs":{"77":{"tf":1.0}}},"df":1,"docs":{"52":{"tf":1.0}},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"79":{"tf":1.0}}}},"df":0,"docs":{}}}}},"h":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":3,"docs":{"35":{"tf":1.0},"68":{"tf":1.0},"75":{"tf":1.4142135623730951}}}},"n":{"c":{"df":2,"docs":{"52":{"tf":1.0},"61":{"tf":1.0}}},"df":0,"docs":{},"g":{"df":6,"docs":{"18":{"tf":1.0},"3":{"tf":1.0},"37":{"tf":1.0},"62":{"tf":1.0},"63":{"tf":1.4142135623730951},"79":{"tf":1.4142135623730951}}}},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":4,"docs":{"11":{"tf":1.0},"58":{"tf":1.0},"77":{"tf":1.0},"86":{"tf":1.0}}}}}},"r":{"df":1,"docs":{"29":{"tf":1.0}}}},"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"k":{"df":2,"docs":{"70":{"tf":1.0},"88":{"tf":1.0}}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"52":{"tf":1.0}}},"df":0,"docs":{}}}},"i":{"df":2,"docs":{"61":{"tf":1.0},"63":{"tf":1.4142135623730951}},"r":{"c":{"df":0,"docs":{},"u":{"df":0,"docs":{},"m":{"df":0,"docs":{},"v":{"df":1,"docs":{"68":{"tf":1.0}}}}}},"df":0,"docs":{}}},"l":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":1,"docs":{"5":{"tf":1.0}}}}},"df":0,"docs":{},"i":{"df":2,"docs":{"11":{"tf":2.0},"18":{"tf":1.0}},"p":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":1,"docs":{"64":{"tf":1.0}}}}}},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":1,"docs":{"77":{"tf":1.0}}}},"s":{"df":0,"docs":{},"e":{"df":3,"docs":{"11":{"tf":1.0},"75":{"tf":1.0},"78":{"tf":1.0}}}}}},"o":{"d":{"df":0,"docs":{},"e":{"b":{"a":{"df":0,"docs":{},"s":{"df":4,"docs":{"58":{"tf":1.0},"61":{"tf":1.0},"62":{"tf":1.4142135623730951},"65":{"tf":1.7320508075688772}}}},"df":0,"docs":{}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":1,"docs":{"42":{"tf":1.0}}}}}},"df":32,"docs":{"0":{"tf":1.0},"12":{"tf":1.4142135623730951},"13":{"tf":1.0},"14":{"tf":1.0},"17":{"tf":1.0},"18":{"tf":1.4142135623730951},"19":{"tf":1.0},"33":{"tf":1.4142135623730951},"35":{"tf":3.0},"36":{"tf":1.0},"37":{"tf":1.0},"39":{"tf":1.0},"4":{"tf":1.0},"41":{"tf":1.0},"42":{"tf":1.0},"43":{"tf":2.23606797749979},"5":{"tf":1.0},"53":{"tf":1.4142135623730951},"6":{"tf":1.0},"64":{"tf":1.4142135623730951},"65":{"tf":1.0},"66":{"tf":1.0},"67":{"tf":1.4142135623730951},"68":{"tf":1.7320508075688772},"69":{"tf":1.4142135623730951},"70":{"tf":1.0},"75":{"tf":2.0},"77":{"tf":1.0},"78":{"tf":1.0},"79":{"tf":1.4142135623730951},"89":{"tf":1.0},"92":{"tf":1.4142135623730951}},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":2,"docs":{"50":{"tf":1.0},"51":{"tf":1.0}}}}},"s":{"df":1,"docs":{"35":{"tf":1.0}}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"79":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}}},"m":{"b":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":2,"docs":{"5":{"tf":1.0},"79":{"tf":1.4142135623730951}}}}},"df":0,"docs":{},"e":{"df":2,"docs":{"53":{"tf":1.0},"77":{"tf":1.0}}},"m":{"a":{"df":0,"docs":{},"n":{"d":{"df":2,"docs":{"19":{"tf":1.0},"30":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"64":{"tf":2.0}}}}},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"52":{"tf":1.0}}}}},"p":{"a":{"df":0,"docs":{},"r":{"df":2,"docs":{"34":{"tf":1.0},"40":{"tf":1.0}},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"0":{"tf":1.0}}}}}}},"t":{"df":8,"docs":{"24":{"tf":1.0},"66":{"tf":1.0},"70":{"tf":1.0},"76":{"tf":1.0},"78":{"tf":1.4142135623730951},"79":{"tf":1.0},"82":{"tf":1.0},"91":{"tf":1.0}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":47,"docs":{"0":{"tf":1.0},"12":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"16":{"tf":1.0},"18":{"tf":2.23606797749979},"19":{"tf":1.0},"22":{"tf":1.0},"24":{"tf":1.0},"25":{"tf":1.0},"3":{"tf":1.0},"33":{"tf":1.0},"39":{"tf":1.0},"4":{"tf":1.7320508075688772},"40":{"tf":1.0},"48":{"tf":1.0},"49":{"tf":1.0},"5":{"tf":2.0},"50":{"tf":1.7320508075688772},"52":{"tf":1.0},"57":{"tf":1.0},"58":{"tf":1.0},"59":{"tf":1.0},"6":{"tf":1.7320508075688772},"60":{"tf":1.0},"61":{"tf":1.0},"62":{"tf":1.0},"65":{"tf":1.0},"66":{"tf":2.0},"67":{"tf":1.7320508075688772},"68":{"tf":1.4142135623730951},"69":{"tf":1.7320508075688772},"70":{"tf":1.0},"71":{"tf":1.4142135623730951},"73":{"tf":1.0},"75":{"tf":2.23606797749979},"76":{"tf":1.0},"77":{"tf":1.0},"78":{"tf":1.4142135623730951},"79":{"tf":1.0},"8":{"tf":1.0},"80":{"tf":1.0},"81":{"tf":1.4142135623730951},"83":{"tf":1.0},"9":{"tf":1.0},"91":{"tf":1.4142135623730951},"92":{"tf":1.0}}}},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":3,"docs":{"11":{"tf":1.0},"75":{"tf":1.0},"92":{"tf":1.0}}},"x":{"df":2,"docs":{"52":{"tf":1.0},"80":{"tf":1.4142135623730951}}}},"i":{"c":{"df":1,"docs":{"62":{"tf":1.0}}},"df":0,"docs":{}}},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"5":{"tf":1.4142135623730951}}},"s":{"df":1,"docs":{"52":{"tf":1.0}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":2,"docs":{"61":{"tf":1.0},"80":{"tf":1.0}}}}}}}},"t":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"4":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}},"u":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"52":{"tf":1.0}}}}}}},"df":1,"docs":{"75":{"tf":1.0}}}}}},"n":{"c":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"43":{"tf":1.0}}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":1,"docs":{"61":{"tf":1.0}}}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":8,"docs":{"13":{"tf":1.0},"14":{"tf":1.0},"24":{"tf":1.0},"25":{"tf":1.0},"27":{"tf":1.7320508075688772},"29":{"tf":1.0},"33":{"tf":1.0},"74":{"tf":1.4142135623730951}}}}}},"l":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"64":{"tf":1.0}}}},"df":0,"docs":{}}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"q":{"df":0,"docs":{},"u":{"df":1,"docs":{"18":{"tf":1.0}},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"14":{"tf":1.0}}}}}}}}},"i":{"d":{"df":5,"docs":{"62":{"tf":1.0},"64":{"tf":1.0},"68":{"tf":1.0},"76":{"tf":1.0},"90":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"52":{"tf":1.0}}}}},"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":2,"docs":{"65":{"tf":1.0},"75":{"tf":1.0}}}}},"t":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":5,"docs":{"14":{"tf":1.0},"43":{"tf":1.0},"45":{"tf":1.0},"47":{"tf":1.0},"64":{"tf":1.0}}}}},"df":0,"docs":{},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"56":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"u":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":6,"docs":{"35":{"tf":1.4142135623730951},"41":{"tf":1.0},"42":{"tf":1.0},"43":{"tf":1.7320508075688772},"51":{"tf":1.7320508075688772},"56":{"tf":1.0}}}}}},"df":0,"docs":{}}}}},"t":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":3,"docs":{"39":{"tf":1.0},"43":{"tf":1.0},"5":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"3":{"tf":1.0}}}},"x":{"df":0,"docs":{},"t":{"df":2,"docs":{"65":{"tf":1.0},"69":{"tf":2.0}}}}},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":34,"docs":{"0":{"tf":2.0},"12":{"tf":1.0},"13":{"tf":1.7320508075688772},"14":{"tf":2.0},"18":{"tf":2.0},"2":{"tf":1.4142135623730951},"27":{"tf":1.4142135623730951},"32":{"tf":2.449489742783178},"33":{"tf":2.0},"35":{"tf":1.4142135623730951},"37":{"tf":1.0},"39":{"tf":1.0},"4":{"tf":1.4142135623730951},"40":{"tf":1.7320508075688772},"43":{"tf":2.0},"44":{"tf":1.0},"45":{"tf":1.0},"50":{"tf":1.0},"51":{"tf":1.4142135623730951},"52":{"tf":1.4142135623730951},"53":{"tf":1.4142135623730951},"55":{"tf":1.0},"56":{"tf":1.4142135623730951},"57":{"tf":1.4142135623730951},"6":{"tf":1.0},"66":{"tf":1.4142135623730951},"68":{"tf":2.0},"70":{"tf":1.0},"75":{"tf":2.23606797749979},"76":{"tf":1.0},"78":{"tf":1.4142135623730951},"79":{"tf":2.0},"89":{"tf":1.0},"91":{"tf":1.4142135623730951}},"s":{".":{"df":0,"docs":{},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"k":{"a":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{".":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":1,"docs":{"2":{"tf":1.0}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"’":{"df":2,"docs":{"13":{"tf":1.0},"14":{"tf":1.0}}}}},"df":0,"docs":{}},"df":0,"docs":{},"i":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":5,"docs":{"13":{"tf":1.0},"14":{"tf":1.0},"59":{"tf":1.0},"63":{"tf":1.4142135623730951},"65":{"tf":2.0}},"o":{"df":0,"docs":{},"r":{"df":5,"docs":{"1":{"tf":1.0},"58":{"tf":1.0},"59":{"tf":1.0},"65":{"tf":1.0},"77":{"tf":1.0}}}}}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"l":{"df":4,"docs":{"13":{"tf":1.0},"55":{"tf":1.0},"70":{"tf":1.0},"82":{"tf":1.0}}}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":3,"docs":{"52":{"tf":1.0},"53":{"tf":1.0},"55":{"tf":1.0}}}}}}},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":3,"docs":{"65":{"tf":1.0},"77":{"tf":1.4142135623730951},"79":{"tf":1.0}}}},"df":0,"docs":{},"s":{"df":0,"docs":{},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"d":{"df":4,"docs":{"18":{"tf":1.0},"26":{"tf":1.0},"27":{"tf":1.4142135623730951},"29":{"tf":1.0}}},"df":0,"docs":{}}}}}}}},"s":{"df":0,"docs":{},"t":{"df":3,"docs":{"13":{"tf":1.4142135623730951},"14":{"tf":1.7320508075688772},"43":{"tf":1.0}}}},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"64":{"tf":1.0}},"p":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":1,"docs":{"79":{"tf":1.0}}}}},"df":0,"docs":{}}}}}},"p":{"df":0,"docs":{},"l":{"df":1,"docs":{"52":{"tf":1.0}}}},"r":{"df":0,"docs":{},"s":{"df":1,"docs":{"52":{"tf":1.0}}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"58":{"tf":1.0}}}}}},"p":{"df":0,"docs":{},"u":{"df":2,"docs":{"74":{"tf":1.4142135623730951},"75":{"tf":1.4142135623730951}}}},"r":{"a":{"df":0,"docs":{},"f":{"df":0,"docs":{},"t":{"df":1,"docs":{"43":{"tf":1.0}}}},"t":{"df":0,"docs":{},"e":{"df":3,"docs":{"62":{"tf":2.449489742783178},"69":{"tf":1.7320508075688772},"71":{"tf":1.4142135623730951}},"s":{"/":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"g":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"/":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"s":{"/":{"df":0,"docs":{},"f":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"p":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{".":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":1,"docs":{"19":{"tf":1.0}}}}}},"df":0,"docs":{}}}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"t":{"df":4,"docs":{"43":{"tf":1.7320508075688772},"62":{"tf":1.0},"65":{"tf":1.0},"80":{"tf":1.0}},"e":{"2":{"df":1,"docs":{"43":{"tf":1.0}}},"df":0,"docs":{}},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"80":{"tf":1.0}}}}}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":4,"docs":{"61":{"tf":1.0},"71":{"tf":1.4142135623730951},"81":{"tf":1.4142135623730951},"83":{"tf":1.4142135623730951}}}}},"u":{"c":{"df":0,"docs":{},"i":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"68":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":2,"docs":{"33":{"tf":1.0},"89":{"tf":1.0}}}}}}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"df":3,"docs":{"71":{"tf":1.0},"72":{"tf":1.4142135623730951},"92":{"tf":1.0}}}}}}}},"d":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"p":{"df":7,"docs":{"1":{"tf":1.0},"18":{"tf":1.0},"34":{"tf":1.0},"39":{"tf":1.0},"52":{"tf":1.4142135623730951},"88":{"tf":1.0},"91":{"tf":1.4142135623730951}}}},"t":{"a":{"_":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"57":{"tf":1.4142135623730951}}}}},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":1,"docs":{"57":{"tf":1.4142135623730951}}}}}},"df":6,"docs":{"18":{"tf":1.0},"35":{"tf":1.0},"49":{"tf":1.0},"57":{"tf":2.0},"70":{"tf":1.0},"79":{"tf":1.4142135623730951}},"o":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":2,"docs":{"43":{"tf":1.0},"44":{"tf":1.0}}}}}}}},"s":{"df":2,"docs":{"43":{"tf":1.0},"45":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{},"e":{"a":{"d":{"df":1,"docs":{"52":{"tf":1.0}}},"df":0,"docs":{},"l":{"df":1,"docs":{"39":{"tf":1.0}}}},"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"_":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":0,"docs":{},"p":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"_":{"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"16":{"tf":1.0}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}},"df":6,"docs":{"16":{"tf":1.7320508075688772},"17":{"tf":1.7320508075688772},"26":{"tf":1.0},"30":{"tf":1.0},"53":{"tf":1.0},"57":{"tf":1.0}}}}},"c":{"df":0,"docs":{},"i":{"d":{"df":2,"docs":{"18":{"tf":1.0},"80":{"tf":1.0}}},"df":0,"docs":{},"s":{"df":3,"docs":{"64":{"tf":1.0},"75":{"tf":1.0},"91":{"tf":1.0}}}},"l":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"79":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":1,"docs":{"69":{"tf":1.0}}}}}}},"d":{"df":0,"docs":{},"i":{"c":{"df":2,"docs":{"62":{"tf":1.0},"69":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"f":{"a":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":5,"docs":{"12":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"15":{"tf":1.0},"17":{"tf":1.0}}}}}},"df":0,"docs":{},"i":{"df":1,"docs":{"52":{"tf":1.0}},"n":{"df":2,"docs":{"77":{"tf":1.0},"79":{"tf":2.0}}}},"u":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"0":{"tf":1.0}}}},"df":0,"docs":{}}}},"g":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":2,"docs":{"64":{"tf":1.0},"65":{"tf":1.0}}}}},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"g":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"c":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"18":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"t":{"df":1,"docs":{"64":{"tf":1.0}}}},"i":{"df":0,"docs":{},"v":{"df":1,"docs":{"92":{"tf":1.0}}}}},"n":{"df":0,"docs":{},"i":{"df":1,"docs":{"63":{"tf":1.0}}}},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"d":{"df":6,"docs":{"18":{"tf":1.4142135623730951},"62":{"tf":3.0},"68":{"tf":1.0},"71":{"tf":1.7320508075688772},"8":{"tf":1.0},"82":{"tf":1.7320508075688772}}},"df":0,"docs":{}}},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"y":{"df":5,"docs":{"18":{"tf":3.1622776601683795},"34":{"tf":1.0},"35":{"tf":1.7320508075688772},"43":{"tf":2.23606797749979},"89":{"tf":1.0}}}}},"r":{"df":0,"docs":{},"e":{"c":{"df":1,"docs":{"52":{"tf":1.0}}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":1,"docs":{"51":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"n":{"df":3,"docs":{"52":{"tf":1.0},"64":{"tf":1.0},"75":{"tf":1.4142135623730951}}}},"r":{"df":2,"docs":{"31":{"tf":1.0},"53":{"tf":1.0}}}},"t":{"df":1,"docs":{"79":{"tf":1.0}}}},"t":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":2,"docs":{"11":{"tf":1.0},"80":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"40":{"tf":1.0}}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"68":{"tf":1.0}}}}}}}}}}},"v":{"df":2,"docs":{"53":{"tf":1.0},"62":{"tf":1.4142135623730951}},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":10,"docs":{"1":{"tf":1.4142135623730951},"16":{"tf":1.0},"17":{"tf":1.0},"20":{"tf":1.0},"30":{"tf":1.0},"34":{"tf":1.0},"52":{"tf":1.0},"58":{"tf":1.0},"61":{"tf":1.4142135623730951},"92":{"tf":1.0}}}}}}}},"i":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"34":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":12,"docs":{"0":{"tf":2.23606797749979},"1":{"tf":1.0},"12":{"tf":1.0},"24":{"tf":1.0},"34":{"tf":1.4142135623730951},"36":{"tf":1.0},"39":{"tf":1.0},"40":{"tf":1.0},"43":{"tf":1.4142135623730951},"50":{"tf":1.7320508075688772},"78":{"tf":1.0},"86":{"tf":1.0}},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":4,"docs":{"35":{"tf":1.0},"68":{"tf":1.0},"79":{"tf":3.0},"80":{"tf":2.0}}}}}}}},"i":{"c":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"47":{"tf":1.0}}}}}}},"df":0,"docs":{}}}},"r":{"df":2,"docs":{"16":{"tf":1.0},"62":{"tf":1.0}},"e":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"19":{"tf":1.0}}}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":4,"docs":{"16":{"tf":1.0},"18":{"tf":1.4142135623730951},"54":{"tf":1.0},"62":{"tf":1.0}}}}}}},"df":0,"docs":{}}},"s":{"a":{"b":{"df":0,"docs":{},"l":{"df":2,"docs":{"17":{"tf":1.0},"18":{"tf":1.0}}}},"df":0,"docs":{}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"g":{"df":2,"docs":{"18":{"tf":1.4142135623730951},"43":{"tf":1.0}}}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":2,"docs":{"63":{"tf":1.0},"65":{"tf":1.0}}}}}},"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":2,"docs":{"71":{"tf":1.0},"9":{"tf":1.0}}}}},"df":0,"docs":{}}}}}},"o":{"c":{"df":1,"docs":{"64":{"tf":1.0}},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"83":{"tf":1.0}}}}}}}},"u":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":2,"docs":{"3":{"tf":1.0},"8":{"tf":1.0}}}}}}}},"df":1,"docs":{"0":{"tf":1.0}},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"n":{"df":0,"docs":{},"’":{"df":0,"docs":{},"t":{"df":5,"docs":{"19":{"tf":1.0},"37":{"tf":1.0},"62":{"tf":1.0},"64":{"tf":1.0},"70":{"tf":1.0}}}}}}},"m":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"72":{"tf":1.0}}}}},"df":0,"docs":{}},"n":{"df":0,"docs":{},"e":{"df":1,"docs":{"18":{"tf":1.0}}},"’":{"df":0,"docs":{},"t":{"df":5,"docs":{"39":{"tf":1.0},"62":{"tf":1.0},"64":{"tf":1.4142135623730951},"71":{"tf":1.0},"85":{"tf":1.0}}}}},"w":{"df":0,"docs":{},"n":{"df":2,"docs":{"53":{"tf":1.0},"75":{"tf":1.0}}}}},"r":{"df":1,"docs":{"91":{"tf":1.0}},"i":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":3,"docs":{"19":{"tf":1.0},"5":{"tf":1.0},"67":{"tf":1.0}}}}}},"o":{"df":0,"docs":{},"p":{"df":1,"docs":{"90":{"tf":1.4142135623730951}}}}},"u":{"df":0,"docs":{},"e":{"df":7,"docs":{"13":{"tf":1.0},"14":{"tf":1.0},"18":{"tf":1.7320508075688772},"43":{"tf":1.0},"68":{"tf":1.0},"72":{"tf":1.0},"78":{"tf":1.0}}},"m":{"df":0,"docs":{},"p":{"df":1,"docs":{"16":{"tf":1.0}}}},"r":{"df":0,"docs":{},"e":{"df":3,"docs":{"18":{"tf":1.4142135623730951},"71":{"tf":1.0},"8":{"tf":1.0}}}}},"y":{"df":0,"docs":{},"n":{"a":{"df":0,"docs":{},"m":{"df":2,"docs":{"14":{"tf":1.0},"68":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{},"e":{"a":{"c":{"df":0,"docs":{},"h":{"df":2,"docs":{"52":{"tf":1.0},"79":{"tf":1.4142135623730951}}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"80":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"i":{"df":1,"docs":{"5":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":2,"docs":{"52":{"tf":1.0},"64":{"tf":1.0}}}}}}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"s":{"df":0,"docs":{},"y":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":1,"docs":{"91":{"tf":1.0}}}}}}}}}},"d":{"df":0,"docs":{},"g":{"df":1,"docs":{"91":{"tf":1.0}}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":2,"docs":{"75":{"tf":1.0},"79":{"tf":1.0}}}},"df":0,"docs":{}},"i":{"c":{"df":0,"docs":{},"i":{"df":1,"docs":{"75":{"tf":1.0}}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":4,"docs":{"52":{"tf":1.0},"64":{"tf":1.0},"66":{"tf":1.0},"91":{"tf":1.0}}}}}}},"l":{"df":0,"docs":{},"f":{"df":5,"docs":{"16":{"tf":1.0},"18":{"tf":1.4142135623730951},"67":{"tf":1.4142135623730951},"74":{"tf":1.0},"81":{"tf":1.0}}},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":2,"docs":{"80":{"tf":1.0},"91":{"tf":1.0}}}}}}},"m":{"b":{"df":0,"docs":{},"e":{"d":{"df":1,"docs":{"75":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":7,"docs":{"18":{"tf":1.0},"35":{"tf":1.0},"39":{"tf":1.0},"67":{"tf":1.0},"69":{"tf":1.0},"70":{"tf":1.4142135623730951},"92":{"tf":1.4142135623730951}}}},"p":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"y":{"df":1,"docs":{"68":{"tf":1.0}}}}},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"57":{"tf":1.0}}}}},"s":{"c":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":3,"docs":{"7":{"tf":1.0},"71":{"tf":1.0},"82":{"tf":1.4142135623730951}}}}}}}}},"d":{"df":0,"docs":{},"k":{"/":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":0,"docs":{},"s":{"d":{"df":0,"docs":{},"k":{"_":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"v":{".":{"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"df":1,"docs":{"82":{"tf":1.0}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":1,"docs":{"82":{"tf":1.0}}}},"df":0,"docs":{}},"u":{"df":0,"docs":{},"l":{"df":3,"docs":{"14":{"tf":1.0},"40":{"tf":1.0},"70":{"tf":1.0}}}}},"n":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"26":{"tf":1.0}}}},"df":0,"docs":{}},"c":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"s":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":2,"docs":{"61":{"tf":1.0},"69":{"tf":1.0}}}}}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"g":{"df":1,"docs":{"77":{"tf":1.0}}}},"df":0,"docs":{}}}}},"d":{"df":1,"docs":{"52":{"tf":1.4142135623730951}},"i":{"a":{"df":0,"docs":{},"n":{"df":1,"docs":{"70":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":2,"docs":{"52":{"tf":1.0},"66":{"tf":1.0}}}},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"df":1,"docs":{"64":{"tf":1.0}}}}}}},"j":{"df":0,"docs":{},"o":{"df":0,"docs":{},"y":{"df":1,"docs":{"65":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":2,"docs":{"64":{"tf":1.0},"65":{"tf":1.0}}}}}},"s":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":3,"docs":{"63":{"tf":1.0},"68":{"tf":1.0},"79":{"tf":1.4142135623730951}}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"r":{"df":1,"docs":{"75":{"tf":1.0}}}},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"91":{"tf":1.0}}},"y":{"df":0,"docs":{},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"5":{"tf":1.0}}}}}}}}}},"v":{"df":1,"docs":{"82":{"tf":1.0}},"i":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":6,"docs":{"53":{"tf":1.0},"55":{"tf":1.0},"72":{"tf":1.0},"76":{"tf":1.7320508075688772},"81":{"tf":1.0},"82":{"tf":1.4142135623730951}}}}}}}},"q":{"df":0,"docs":{},"u":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"35":{"tf":1.0}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"l":{"df":2,"docs":{"4":{"tf":1.0},"75":{"tf":1.0}}}},"df":0,"docs":{}}}}},"r":{"df":0,"docs":{},"r":{"(":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{":":{":":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"(":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"d":{"a":{"df":0,"docs":{},"t":{"a":{"df":1,"docs":{"57":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":5,"docs":{"39":{"tf":1.0},"40":{"tf":1.0},"48":{"tf":1.0},"49":{"tf":1.0},"79":{"tf":1.0}}}}}},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"u":{"df":0,"docs":{},"m":{"/":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"d":{"/":{"b":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"/":{":":{"$":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"77":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":13,"docs":{"0":{"tf":1.0},"11":{"tf":1.0},"34":{"tf":1.0},"4":{"tf":1.0},"40":{"tf":1.0},"49":{"tf":1.0},"6":{"tf":1.0},"66":{"tf":1.4142135623730951},"77":{"tf":1.7320508075688772},"78":{"tf":1.4142135623730951},"79":{"tf":2.23606797749979},"8":{"tf":1.0},"91":{"tf":1.0}}}}}}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":4,"docs":{"52":{"tf":1.0},"65":{"tf":1.0},"75":{"tf":1.0},"91":{"tf":1.0}},"t":{"df":0,"docs":{},"u":{"df":2,"docs":{"13":{"tf":1.0},"14":{"tf":1.0}}}}}},"m":{".":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"33":{"tf":1.0}}}},"df":0,"docs":{}}}}}},"b":{"df":0,"docs":{},"y":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"o":{"d":{"df":1,"docs":{"33":{"tf":1.7320508075688772}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"33":{"tf":1.7320508075688772}}}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}}},"df":20,"docs":{"0":{"tf":1.4142135623730951},"1":{"tf":1.0},"14":{"tf":1.4142135623730951},"33":{"tf":1.4142135623730951},"34":{"tf":1.4142135623730951},"35":{"tf":1.0},"4":{"tf":1.0},"40":{"tf":1.4142135623730951},"43":{"tf":1.4142135623730951},"48":{"tf":1.0},"51":{"tf":1.0},"52":{"tf":1.7320508075688772},"70":{"tf":2.0},"72":{"tf":1.4142135623730951},"75":{"tf":2.23606797749979},"77":{"tf":1.0},"78":{"tf":1.0},"79":{"tf":2.6457513110645907},"85":{"tf":1.4142135623730951},"89":{"tf":1.0}}}},"x":{"a":{"c":{"df":0,"docs":{},"t":{"df":3,"docs":{"18":{"tf":1.0},"74":{"tf":1.0},"80":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":2,"docs":{"68":{"tf":1.0},"79":{"tf":1.0}}}}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":13,"docs":{"0":{"tf":1.0},"18":{"tf":1.0},"5":{"tf":1.0},"51":{"tf":1.0},"52":{"tf":1.4142135623730951},"57":{"tf":1.0},"61":{"tf":1.0},"63":{"tf":1.0},"68":{"tf":1.0},"79":{"tf":1.4142135623730951},"80":{"tf":1.0},"82":{"tf":1.0},"83":{"tf":1.0}}}}}},"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":1,"docs":{"52":{"tf":1.0}}},"p":{"df":0,"docs":{},"t":{"df":1,"docs":{"63":{"tf":1.0}}}}}},"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":15,"docs":{"12":{"tf":1.7320508075688772},"13":{"tf":1.0},"14":{"tf":1.0},"15":{"tf":1.0},"39":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.4142135623730951},"55":{"tf":1.4142135623730951},"57":{"tf":1.0},"75":{"tf":1.4142135623730951},"79":{"tf":2.449489742783178},"80":{"tf":1.0},"81":{"tf":1.0},"82":{"tf":1.0},"83":{"tf":1.0}}}}},"df":0,"docs":{}},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":2,"docs":{"11":{"tf":1.0},"89":{"tf":1.0}}}}},"p":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":4,"docs":{"43":{"tf":1.4142135623730951},"52":{"tf":1.0},"64":{"tf":1.0},"79":{"tf":1.4142135623730951}}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":2,"docs":{"52":{"tf":1.0},"75":{"tf":1.7320508075688772}}}},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"52":{"tf":1.0}}}}},"l":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":4,"docs":{"11":{"tf":1.0},"18":{"tf":1.0},"64":{"tf":1.0},"77":{"tf":1.0}}}}},"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"18":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"33":{"tf":1.0}}}}}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"22":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"14":{"tf":1.0}}}}}}},"r":{"df":0,"docs":{},"t":{"df":2,"docs":{"77":{"tf":1.0},"82":{"tf":1.4142135623730951}}}},"s":{"df":3,"docs":{"12":{"tf":1.0},"19":{"tf":1.0},"76":{"tf":1.0}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"64":{"tf":1.7320508075688772}}}}}}},"t":{"c":{"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":1,"docs":{"48":{"tf":1.0}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":1,"docs":{"18":{"tf":1.4142135623730951}}}}}}}},"f":{"a":{"c":{"df":0,"docs":{},"e":{"df":1,"docs":{"5":{"tf":1.0}}},"t":{"df":3,"docs":{"18":{"tf":1.0},"65":{"tf":1.0},"75":{"tf":1.0}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"18":{"tf":1.4142135623730951}}}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":3,"docs":{"18":{"tf":1.4142135623730951},"65":{"tf":1.0},"89":{"tf":1.0}}}},"l":{"df":0,"docs":{},"l":{"df":2,"docs":{"43":{"tf":1.0},"75":{"tf":1.0}}}},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"43":{"tf":1.0}}}}}},"q":{"df":1,"docs":{"84":{"tf":1.0}}},"r":{"df":2,"docs":{"52":{"tf":1.0},"75":{"tf":1.0}}},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"52":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"4":{"tf":1.0},"75":{"tf":1.0}}}}}}},"df":1,"docs":{"57":{"tf":1.0}},"e":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"66":{"tf":1.0}}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":6,"docs":{"18":{"tf":1.0},"4":{"tf":1.0},"77":{"tf":1.0},"86":{"tf":1.0},"88":{"tf":1.0},"92":{"tf":1.0}}}}}},"df":0,"docs":{},"w":{"df":4,"docs":{"11":{"tf":1.0},"24":{"tf":1.0},"40":{"tf":1.0},"64":{"tf":1.0}}}},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"d":{"df":2,"docs":{"32":{"tf":2.0},"33":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"l":{"df":0,"docs":{},"e":{"df":7,"docs":{"16":{"tf":1.0},"17":{"tf":1.0},"32":{"tf":2.8284271247461903},"33":{"tf":1.4142135623730951},"57":{"tf":1.0},"62":{"tf":1.4142135623730951},"67":{"tf":1.0}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"55":{"tf":1.0}}}}}},"n":{"a":{"df":0,"docs":{},"l":{"df":3,"docs":{"67":{"tf":1.0},"79":{"tf":1.0},"82":{"tf":1.4142135623730951}}}},"d":{"df":3,"docs":{"1":{"tf":1.0},"7":{"tf":1.0},"88":{"tf":1.0}}},"df":0,"docs":{},"e":{"df":6,"docs":{"0":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"55":{"tf":1.0},"61":{"tf":1.0},"68":{"tf":1.0}}},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"df":1,"docs":{"57":{"tf":1.4142135623730951}}}},"t":{"df":1,"docs":{"14":{"tf":1.0}}}}},"r":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":2,"docs":{"32":{"tf":1.0},"92":{"tf":1.0}}}}},"x":{"df":5,"docs":{"0":{"tf":1.4142135623730951},"40":{"tf":1.4142135623730951},"63":{"tf":1.0},"65":{"tf":1.0},"77":{"tf":1.0}}}},"l":{"a":{"df":0,"docs":{},"g":{"df":3,"docs":{"18":{"tf":1.0},"57":{"tf":2.0},"70":{"tf":1.0}}},"w":{"df":1,"docs":{"75":{"tf":1.4142135623730951}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"p":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{".":{"df":0,"docs":{},"p":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{"df":1,"docs":{"57":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}}}}}}},"o":{"c":{"df":0,"docs":{},"u":{"df":1,"docs":{"92":{"tf":1.0}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":13,"docs":{"10":{"tf":1.0},"12":{"tf":1.0},"36":{"tf":1.0},"52":{"tf":1.0},"6":{"tf":1.0},"64":{"tf":1.0},"65":{"tf":1.0},"67":{"tf":1.4142135623730951},"68":{"tf":1.0},"7":{"tf":1.0},"78":{"tf":1.0},"79":{"tf":1.0},"80":{"tf":1.0}}}}}},"r":{"c":{"df":1,"docs":{"63":{"tf":1.0}}},"df":0,"docs":{},"k":{"df":2,"docs":{"21":{"tf":1.7320508075688772},"23":{"tf":1.0}}},"m":{"a":{"df":0,"docs":{},"t":{"df":3,"docs":{"18":{"tf":1.0},"79":{"tf":1.0},"80":{"tf":1.0}},"t":{"df":1,"docs":{"64":{"tf":1.0}}}}},"df":0,"docs":{}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"e":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"65":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"u":{"df":0,"docs":{},"m":{"df":1,"docs":{"22":{"tf":1.0}}}}},"u":{"df":0,"docs":{},"n":{"d":{"df":5,"docs":{"18":{"tf":1.0},"3":{"tf":1.0},"62":{"tf":1.0},"74":{"tf":1.0},"75":{"tf":1.0}},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"21":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}}}},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"75":{"tf":1.0}}}}}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":1,"docs":{"57":{"tf":1.4142135623730951}},"w":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"k":{"df":1,"docs":{"66":{"tf":1.0}}}}}}}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"d":{"df":5,"docs":{"5":{"tf":1.0},"6":{"tf":1.0},"66":{"tf":1.0},"81":{"tf":1.0},"82":{"tf":1.0}}},"df":0,"docs":{}}}}}}},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":1,"docs":{"33":{"tf":1.0}},"i":{"df":4,"docs":{"63":{"tf":1.0},"64":{"tf":1.0},"68":{"tf":1.4142135623730951},"74":{"tf":1.0}}}}},"n":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":6,"docs":{"39":{"tf":1.7320508075688772},"40":{"tf":1.0},"51":{"tf":1.4142135623730951},"64":{"tf":1.4142135623730951},"71":{"tf":1.0},"92":{"tf":1.0}}}}}}},"d":{"df":1,"docs":{"65":{"tf":1.0}}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":3,"docs":{"79":{"tf":1.0},"80":{"tf":1.0},"89":{"tf":1.0}},"m":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":2,"docs":{"71":{"tf":1.0},"72":{"tf":1.0}}}}}}}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"43":{"tf":1.0}}}},"u":{"df":0,"docs":{},"r":{"df":3,"docs":{"18":{"tf":1.0},"65":{"tf":1.0},"89":{"tf":1.0}}}}}}},"g":{"a":{"df":8,"docs":{"0":{"tf":1.7320508075688772},"13":{"tf":1.0},"14":{"tf":1.4142135623730951},"37":{"tf":1.7320508075688772},"40":{"tf":1.0},"43":{"tf":1.4142135623730951},"70":{"tf":1.0},"72":{"tf":1.0}},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"75":{"tf":1.0}}}},"s":{"_":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":0,"docs":{},"u":{"df":0,"docs":{},"m":{"df":1,"docs":{"57":{"tf":2.449489742783178}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"v":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"91":{"tf":1.0}}}}}},"df":2,"docs":{"17":{"tf":1.0},"26":{"tf":1.0}},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":16,"docs":{"17":{"tf":1.0},"2":{"tf":1.0},"33":{"tf":2.0},"40":{"tf":1.0},"5":{"tf":1.0},"52":{"tf":1.0},"6":{"tf":1.0},"61":{"tf":1.0},"64":{"tf":1.0},"65":{"tf":2.0},"66":{"tf":1.0},"68":{"tf":1.0},"69":{"tf":1.4142135623730951},"75":{"tf":1.0},"77":{"tf":1.0},"88":{"tf":1.0}}}}},"t":{"df":4,"docs":{"1":{"tf":1.0},"52":{"tf":1.0},"58":{"tf":1.0},"60":{"tf":1.0}}}},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"77":{"tf":1.0}},"h":{"df":0,"docs":{},"u":{"b":{"df":1,"docs":{"63":{"tf":1.0}}},"df":0,"docs":{}}}},"v":{"df":0,"docs":{},"e":{"df":1,"docs":{"92":{"tf":1.0}},"n":{"df":3,"docs":{"65":{"tf":1.0},"68":{"tf":1.0},"92":{"tf":1.0}}}}}},"l":{"a":{"d":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"59":{"tf":1.0}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"o":{"d":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{".":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":1,"docs":{"22":{"tf":1.0}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":2,"docs":{"77":{"tf":1.4142135623730951},"79":{"tf":1.4142135623730951}},"e":{"df":1,"docs":{"77":{"tf":1.0}}},"o":{"d":{"df":2,"docs":{"61":{"tf":1.0},"66":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"r":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"55":{"tf":1.0}}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"52":{"tf":1.0}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"61":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"w":{"df":1,"docs":{"14":{"tf":1.0}}}}},"u":{"a":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":1,"docs":{"75":{"tf":1.0}}}}}},"df":0,"docs":{}}},"df":0,"docs":{},"i":{"d":{"df":6,"docs":{"1":{"tf":1.4142135623730951},"4":{"tf":1.0},"58":{"tf":1.0},"59":{"tf":1.0},"64":{"tf":1.0},"78":{"tf":1.0}}},"df":0,"docs":{}}}},"h":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"f":{"df":1,"docs":{"75":{"tf":1.0}}},"l":{"df":0,"docs":{},"u":{"c":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"65":{"tf":1.0}}}}},"df":0,"docs":{}}}},"n":{"d":{"df":1,"docs":{"75":{"tf":1.0}},"i":{"df":1,"docs":{"53":{"tf":1.0}}}},"df":0,"docs":{}},"p":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":2,"docs":{"18":{"tf":1.4142135623730951},"67":{"tf":1.0}}}}}},"r":{"d":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"21":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"w":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"75":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"s":{"df":0,"docs":{},"h":{"df":7,"docs":{"0":{"tf":1.0},"18":{"tf":1.0},"38":{"tf":1.0},"43":{"tf":2.0},"44":{"tf":1.0},"45":{"tf":1.0},"68":{"tf":1.0}},"m":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"68":{"tf":1.0}}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"e":{"a":{"d":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{},"p":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"z":{"df":1,"docs":{"14":{"tf":1.0}}}}}},"df":5,"docs":{"0":{"tf":1.0},"14":{"tf":2.449489742783178},"27":{"tf":1.4142135623730951},"40":{"tf":1.0},"70":{"tf":2.0}}},"v":{"df":0,"docs":{},"i":{"df":1,"docs":{"66":{"tf":1.0}}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":1,"docs":{"0":{"tf":1.0}}}},"p":{"df":4,"docs":{"1":{"tf":1.0},"11":{"tf":1.7320508075688772},"54":{"tf":1.4142135623730951},"58":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"79":{"tf":1.0}}}}}},"n":{"c":{"df":1,"docs":{"70":{"tf":1.0}}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"e":{"df":4,"docs":{"51":{"tf":1.0},"65":{"tf":1.0},"74":{"tf":1.0},"88":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":4,"docs":{"4":{"tf":1.0},"66":{"tf":1.0},"79":{"tf":1.0},"91":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":3,"docs":{"34":{"tf":1.0},"64":{"tf":1.0},"78":{"tf":1.0}}}}}}}}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"69":{"tf":1.0}}}}}}},"o":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":1,"docs":{"65":{"tf":1.0}}}},"o":{"d":{"df":1,"docs":{"67":{"tf":1.0}}},"df":0,"docs":{}},"s":{"df":0,"docs":{},"t":{"df":2,"docs":{"76":{"tf":1.4142135623730951},"82":{"tf":1.0}}}}},"t":{"df":0,"docs":{},"t":{"df":0,"docs":{},"p":{"df":0,"docs":{},"s":{":":{"/":{"/":{"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"u":{"b":{".":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"/":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"u":{"df":0,"docs":{},"m":{"/":{"df":0,"docs":{},"g":{"df":0,"docs":{},"o":{"df":1,"docs":{"77":{"tf":1.0}}}}},"df":0,"docs":{}}}}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"u":{"b":{"df":1,"docs":{"76":{"tf":1.0}}},"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"n":{"df":1,"docs":{"65":{"tf":1.0}}}},"df":0,"docs":{}}}},"i":{".":{"df":1,"docs":{"18":{"tf":1.4142135623730951}}},"d":{"df":2,"docs":{"23":{"tf":1.4142135623730951},"33":{"tf":1.0}},"e":{"a":{"df":1,"docs":{"52":{"tf":1.0}},"l":{"df":1,"docs":{"75":{"tf":1.0}}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":2,"docs":{"68":{"tf":1.0},"80":{"tf":1.0}}}}}}}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"n":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":3,"docs":{"0":{"tf":1.0},"41":{"tf":1.0},"75":{"tf":1.4142135623730951}}}}}},"m":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":12,"docs":{"0":{"tf":1.4142135623730951},"4":{"tf":1.0},"52":{"tf":2.449489742783178},"6":{"tf":1.0},"62":{"tf":1.0},"69":{"tf":2.23606797749979},"72":{"tf":1.0},"75":{"tf":1.0},"77":{"tf":1.7320508075688772},"78":{"tf":1.0},"79":{"tf":1.7320508075688772},"80":{"tf":1.4142135623730951}}}}}}},"i":{"df":2,"docs":{"18":{"tf":1.0},"40":{"tf":1.0}}}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":3,"docs":{"1":{"tf":1.0},"64":{"tf":1.0},"65":{"tf":1.0}}}}},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"v":{"df":2,"docs":{"88":{"tf":1.0},"92":{"tf":1.0}}}}}}},"n":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":2,"docs":{"13":{"tf":1.0},"14":{"tf":1.0}}}}}}},"l":{"df":0,"docs":{},"u":{"d":{"df":8,"docs":{"13":{"tf":1.0},"14":{"tf":1.0},"16":{"tf":1.0},"33":{"tf":1.0},"4":{"tf":1.0},"52":{"tf":1.0},"55":{"tf":1.0},"62":{"tf":1.0}}},"df":0,"docs":{}}},"o":{"df":0,"docs":{},"m":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"18":{"tf":1.0}}}}}}}},"r":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"s":{"df":3,"docs":{"13":{"tf":1.7320508075688772},"14":{"tf":1.0},"89":{"tf":1.0}}}},"df":0,"docs":{}}}},"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"76":{"tf":1.0}}}}}}}},"u":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":2,"docs":{"52":{"tf":1.0},"75":{"tf":1.0}}}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"i":{"df":2,"docs":{"52":{"tf":1.0},"75":{"tf":1.0}}}},"df":0,"docs":{}}}}},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"14":{"tf":1.0}}}}}},"o":{"df":1,"docs":{"17":{"tf":1.0}},"r":{"df":0,"docs":{},"m":{"df":3,"docs":{"17":{"tf":1.0},"2":{"tf":1.0},"26":{"tf":1.0}}}}},"r":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"u":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"5":{"tf":1.0}}}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"52":{"tf":1.0},"65":{"tf":1.0}},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"51":{"tf":1.0}}}}}}},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":3,"docs":{"30":{"tf":1.0},"51":{"tf":1.4142135623730951},"76":{"tf":1.0}}}}},"k":{"df":0,"docs":{},"w":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":1,"docs":{"71":{"tf":1.0}}}}}},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":4,"docs":{"18":{"tf":2.23606797749979},"4":{"tf":1.0},"64":{"tf":1.0},"86":{"tf":1.4142135623730951}}}}},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"u":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"d":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"d":{"df":1,"docs":{"51":{"tf":1.7320508075688772}}},"df":0,"docs":{}}}}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}},"t":{"df":0,"docs":{},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"51":{"tf":1.7320508075688772}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}},"p":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"18":{"tf":1.0}}}}}},"df":3,"docs":{"18":{"tf":1.4142135623730951},"22":{"tf":1.0},"24":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"i":{"d":{"df":5,"docs":{"18":{"tf":1.0},"43":{"tf":1.0},"54":{"tf":1.0},"70":{"tf":1.0},"80":{"tf":1.0}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":1,"docs":{"55":{"tf":1.0}}}}}},"t":{"a":{"df":0,"docs":{},"l":{"df":7,"docs":{"54":{"tf":2.23606797749979},"6":{"tf":1.4142135623730951},"61":{"tf":1.0},"7":{"tf":1.0},"77":{"tf":1.0},"8":{"tf":1.4142135623730951},"82":{"tf":1.4142135623730951}}},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":4,"docs":{"0":{"tf":1.0},"43":{"tf":1.0},"56":{"tf":1.4142135623730951},"79":{"tf":1.7320508075688772}}}}}},"df":0,"docs":{},"e":{"a":{"d":{"df":10,"docs":{"0":{"tf":1.4142135623730951},"14":{"tf":1.0},"18":{"tf":1.0},"35":{"tf":1.4142135623730951},"38":{"tf":1.0},"43":{"tf":1.4142135623730951},"53":{"tf":1.0},"64":{"tf":1.0},"68":{"tf":1.0},"79":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"u":{"c":{"df":0,"docs":{},"t":{"df":7,"docs":{"10":{"tf":1.0},"18":{"tf":1.0},"35":{"tf":1.0},"43":{"tf":1.0},"55":{"tf":1.0},"75":{"tf":1.0},"8":{"tf":1.0}}}},"df":0,"docs":{}}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"g":{"df":0,"docs":{},"r":{"df":4,"docs":{"20":{"tf":1.4142135623730951},"52":{"tf":1.0},"77":{"tf":1.7320508075688772},"79":{"tf":2.0}}}},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"76":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"f":{"a":{"c":{"df":5,"docs":{"24":{"tf":1.4142135623730951},"52":{"tf":1.0},"69":{"tf":1.0},"71":{"tf":1.7320508075688772},"76":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"m":{"df":0,"docs":{},"e":{"d":{"df":0,"docs":{},"i":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"16":{"tf":1.0}}}}},"df":2,"docs":{"66":{"tf":1.0},"67":{"tf":1.0}}}},"df":0,"docs":{}}},"n":{"df":4,"docs":{"51":{"tf":1.4142135623730951},"58":{"tf":1.0},"66":{"tf":1.0},"68":{"tf":1.0}}},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"75":{"tf":1.4142135623730951}}}}}}}},"r":{"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"u":{"c":{"df":3,"docs":{"0":{"tf":1.4142135623730951},"1":{"tf":1.0},"52":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"u":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"64":{"tf":1.0}}}}}},"v":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"d":{"df":1,"docs":{"68":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"v":{"df":2,"docs":{"18":{"tf":1.0},"65":{"tf":1.4142135623730951}}}}}}},"r":{"df":7,"docs":{"16":{"tf":1.4142135623730951},"50":{"tf":1.7320508075688772},"51":{"tf":1.0},"66":{"tf":1.4142135623730951},"67":{"tf":1.4142135623730951},"69":{"tf":1.0},"72":{"tf":1.0}},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"33":{"tf":1.0}}}}}}}},"s":{"a":{"df":1,"docs":{"75":{"tf":1.0}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"’":{"df":0,"docs":{},"t":{"df":4,"docs":{"0":{"tf":1.0},"18":{"tf":1.0},"75":{"tf":1.0},"78":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"u":{"df":1,"docs":{"63":{"tf":1.0}}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":1,"docs":{"64":{"tf":1.0}}},"r":{"df":1,"docs":{"68":{"tf":1.0}}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"f":{"df":4,"docs":{"5":{"tf":1.0},"52":{"tf":1.0},"63":{"tf":1.0},"71":{"tf":1.0}}}}}},"’":{"d":{"df":1,"docs":{"51":{"tf":1.0}}},"df":6,"docs":{"18":{"tf":1.0},"19":{"tf":1.0},"52":{"tf":1.0},"53":{"tf":1.0},"55":{"tf":1.0},"90":{"tf":1.0}}}}},"j":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":2,"docs":{"4":{"tf":1.0},"75":{"tf":2.23606797749979}}}},"s":{"df":1,"docs":{"19":{"tf":1.0}},"o":{"df":0,"docs":{},"n":{"df":3,"docs":{"18":{"tf":1.4142135623730951},"24":{"tf":1.4142135623730951},"33":{"tf":1.4142135623730951}}}}},"u":{"d":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"65":{"tf":1.0}}}}}}}}},"df":0,"docs":{}}},"k":{"b":{"df":1,"docs":{"57":{"tf":1.0}}},"df":0,"docs":{},"e":{"c":{"c":{"a":{"df":0,"docs":{},"k":{"2":{"5":{"6":{"df":1,"docs":{"38":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{},"e":{"df":0,"docs":{},"p":{"df":5,"docs":{"11":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"65":{"tf":1.0},"91":{"tf":1.0}}}},"p":{"df":0,"docs":{},"t":{"df":2,"docs":{"61":{"tf":1.0},"70":{"tf":1.0}}}},"y":{"df":2,"docs":{"32":{"tf":1.7320508075688772},"79":{"tf":1.0}},"w":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"43":{"tf":1.0}}},"df":0,"docs":{}}}}}},"n":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":3,"docs":{"11":{"tf":1.0},"18":{"tf":1.0},"52":{"tf":1.0}},"l":{"df":0,"docs":{},"e":{"d":{"df":0,"docs":{},"g":{"df":1,"docs":{"72":{"tf":1.0}}}},"df":0,"docs":{}}},"n":{"df":1,"docs":{"18":{"tf":1.0}}}}}}},"l":{"a":{"c":{"df":0,"docs":{},"k":{"df":2,"docs":{"14":{"tf":1.0},"72":{"tf":1.0}}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"u":{"a":{"df":0,"docs":{},"g":{"df":4,"docs":{"22":{"tf":1.0},"52":{"tf":2.6457513110645907},"64":{"tf":1.0},"91":{"tf":1.0}}}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"g":{"df":2,"docs":{"65":{"tf":1.0},"80":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"40":{"tf":1.0},"89":{"tf":1.0}}}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"88":{"tf":1.7320508075688772}}}}}},"u":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"h":{"df":1,"docs":{"76":{"tf":1.0}}}},"df":0,"docs":{}}},"y":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"72":{"tf":1.0}}}},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"40":{"tf":1.0}}}}}}},"df":0,"docs":{},"e":{"a":{"d":{"df":4,"docs":{"0":{"tf":1.0},"39":{"tf":1.0},"40":{"tf":1.0},"65":{"tf":1.0}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":1,"docs":{"61":{"tf":1.0}}}},"v":{"df":1,"docs":{"71":{"tf":1.0}}}},"df":1,"docs":{"72":{"tf":1.0}},"g":{"a":{"c":{"df":0,"docs":{},"i":{"df":1,"docs":{"51":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"75":{"tf":1.0}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":10,"docs":{"12":{"tf":2.0},"32":{"tf":3.1622776601683795},"33":{"tf":1.4142135623730951},"39":{"tf":1.0},"4":{"tf":1.0},"40":{"tf":1.0},"52":{"tf":1.7320508075688772},"55":{"tf":1.0},"66":{"tf":1.0},"79":{"tf":1.0}}}}},"x":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"69":{"tf":1.0}}}}}},"i":{"b":{"c":{"df":1,"docs":{"83":{"tf":1.0}}},"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":9,"docs":{"18":{"tf":3.4641016151377544},"5":{"tf":1.0},"52":{"tf":2.0},"62":{"tf":1.0},"67":{"tf":1.0},"68":{"tf":1.0},"69":{"tf":1.7320508075688772},"76":{"tf":1.0},"79":{"tf":1.7320508075688772}}}}},"df":0,"docs":{}}},"df":2,"docs":{"65":{"tf":1.0},"91":{"tf":1.0}},"f":{"df":0,"docs":{},"t":{"df":1,"docs":{"66":{"tf":1.0}}}},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":3,"docs":{"37":{"tf":1.0},"40":{"tf":1.0},"89":{"tf":1.0}}}}},"n":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"r":{"df":3,"docs":{"40":{"tf":1.0},"70":{"tf":1.0},"75":{"tf":1.0}}}},"df":3,"docs":{"19":{"tf":1.0},"30":{"tf":1.0},"64":{"tf":1.0}}},"k":{"a":{"df":0,"docs":{},"g":{"df":1,"docs":{"18":{"tf":1.0}}}},"df":5,"docs":{"18":{"tf":3.605551275463989},"52":{"tf":1.0},"67":{"tf":1.0},"68":{"tf":1.4142135623730951},"81":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":4,"docs":{"18":{"tf":1.4142135623730951},"67":{"tf":1.0},"71":{"tf":1.0},"74":{"tf":1.0}}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"64":{"tf":1.0}}}}},"u":{"df":0,"docs":{},"x":{"df":2,"docs":{"7":{"tf":1.0},"81":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"39":{"tf":1.0}}}},"t":{"df":0,"docs":{},"t":{"df":0,"docs":{},"l":{"df":1,"docs":{"62":{"tf":1.0}}}}},"v":{"df":0,"docs":{},"e":{"df":3,"docs":{"35":{"tf":1.0},"62":{"tf":1.0},"75":{"tf":1.0}}}}},"l":{"d":{"df":3,"docs":{"67":{"tf":1.0},"71":{"tf":1.4142135623730951},"82":{"tf":1.0}}},"df":1,"docs":{"69":{"tf":1.0}},"m":{"df":1,"docs":{"65":{"tf":1.0}}},"v":{"df":0,"docs":{},"m":{"/":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":0,"docs":{},"s":{"c":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"/":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"82":{"tf":1.0}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}}}},"g":{"df":0,"docs":{},"n":{"df":0,"docs":{},"u":{"/":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"82":{"tf":1.0}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"y":{"df":0,"docs":{},"s":{"_":{"1":{"8":{"1":{"_":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"x":{"=":{"$":{"df":0,"docs":{},"{":{"df":0,"docs":{},"p":{"df":0,"docs":{},"w":{"d":{"df":0,"docs":{},"}":{"/":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"82":{"tf":1.0}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":13,"docs":{"12":{"tf":1.4142135623730951},"16":{"tf":1.0},"29":{"tf":1.0},"30":{"tf":1.0},"5":{"tf":1.0},"52":{"tf":1.0},"66":{"tf":1.4142135623730951},"67":{"tf":1.4142135623730951},"69":{"tf":2.449489742783178},"71":{"tf":2.449489742783178},"72":{"tf":1.4142135623730951},"82":{"tf":3.0},"92":{"tf":1.0}}}}},"o":{"c":{"a":{"df":0,"docs":{},"l":{"df":4,"docs":{"13":{"tf":1.0},"53":{"tf":1.0},"61":{"tf":1.0},"63":{"tf":1.0}}},"t":{"df":1,"docs":{"62":{"tf":1.0}}}},"df":0,"docs":{},"k":{"df":1,"docs":{"62":{"tf":1.4142135623730951}}}},"df":0,"docs":{},"g":{"df":1,"docs":{"55":{"tf":2.23606797749979}},"i":{"c":{"df":4,"docs":{"52":{"tf":1.0},"69":{"tf":1.4142135623730951},"77":{"tf":1.0},"79":{"tf":1.0}}},"df":0,"docs":{}}},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"23":{"tf":1.0}}}}}},"o":{"df":0,"docs":{},"k":{"df":1,"docs":{"91":{"tf":1.0}}}},"s":{"df":0,"docs":{},"e":{"df":1,"docs":{"75":{"tf":1.0}}},"s":{"df":1,"docs":{"65":{"tf":1.0}}}},"t":{"df":2,"docs":{"79":{"tf":1.0},"80":{"tf":1.0}}},"w":{"df":5,"docs":{"39":{"tf":1.0},"40":{"tf":1.0},"52":{"tf":1.0},"55":{"tf":1.0},"91":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":4,"docs":{"52":{"tf":1.4142135623730951},"66":{"tf":1.0},"67":{"tf":1.4142135623730951},"69":{"tf":1.0}}}}}}},"m":{"a":{"c":{"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":2,"docs":{"13":{"tf":1.0},"72":{"tf":1.4142135623730951}}}}},"o":{"df":1,"docs":{"7":{"tf":1.0}}},"r":{"df":0,"docs":{},"o":{"df":1,"docs":{"64":{"tf":1.4142135623730951}}}}},"d":{"df":0,"docs":{},"e":{"df":1,"docs":{"63":{"tf":1.0}}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"64":{"tf":1.0}}},"df":0,"docs":{}},"n":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"d":{"df":1,"docs":{"75":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}}}},"i":{"df":0,"docs":{},"n":{"df":4,"docs":{"63":{"tf":1.0},"69":{"tf":1.0},"75":{"tf":1.0},"92":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":3,"docs":{"18":{"tf":1.0},"30":{"tf":1.0},"66":{"tf":1.0}}}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"m":{"df":1,"docs":{"52":{"tf":1.0}}}},"df":0,"docs":{}}}}},"t":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":7,"docs":{"23":{"tf":1.0},"60":{"tf":1.0},"63":{"tf":1.0},"65":{"tf":1.7320508075688772},"66":{"tf":1.0},"68":{"tf":1.0},"71":{"tf":1.0}}}}},"df":0,"docs":{}}}},"j":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":2,"docs":{"7":{"tf":1.0},"92":{"tf":1.4142135623730951}}}}},"k":{"df":0,"docs":{},"e":{"df":13,"docs":{"18":{"tf":1.4142135623730951},"19":{"tf":1.0},"3":{"tf":1.0},"43":{"tf":1.0},"52":{"tf":1.0},"54":{"tf":1.0},"61":{"tf":1.0},"63":{"tf":1.0},"64":{"tf":1.0},"68":{"tf":1.0},"70":{"tf":1.0},"77":{"tf":1.0},"82":{"tf":1.7320508075688772}},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"61":{"tf":1.4142135623730951}}}}}}},"n":{"a":{"df":0,"docs":{},"g":{"df":1,"docs":{"77":{"tf":1.0}}}},"df":0,"docs":{},"i":{"df":2,"docs":{"39":{"tf":1.0},"5":{"tf":1.4142135623730951}},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":1,"docs":{"91":{"tf":1.0}}}}}}}},"u":{"a":{"df":0,"docs":{},"l":{"df":2,"docs":{"43":{"tf":1.0},"79":{"tf":1.0}}}},"df":0,"docs":{}}},"p":{"df":1,"docs":{"75":{"tf":1.0}}},"t":{"c":{"df":0,"docs":{},"h":{"df":1,"docs":{"79":{"tf":1.0}}}},"df":0,"docs":{}},"x":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"u":{"df":0,"docs":{},"m":{"df":1,"docs":{"40":{"tf":1.0}}}}}}},"y":{"b":{"df":1,"docs":{"52":{"tf":1.0}}},"df":0,"docs":{}}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":1,"docs":{"40":{"tf":1.0}}}}}},"d":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"k":{"df":1,"docs":{"3":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"n":{"df":2,"docs":{"40":{"tf":1.0},"64":{"tf":1.0}},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":1,"docs":{"64":{"tf":1.7320508075688772}}}}}},"s":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"68":{"tf":1.0}}}}}},"c":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"df":1,"docs":{"18":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":7,"docs":{"13":{"tf":1.7320508075688772},"14":{"tf":2.449489742783178},"27":{"tf":1.0},"39":{"tf":1.7320508075688772},"40":{"tf":2.8284271247461903},"57":{"tf":1.0},"70":{"tf":1.7320508075688772}}}}}},"r":{"df":0,"docs":{},"g":{"df":1,"docs":{"63":{"tf":1.0}}}},"s":{"df":0,"docs":{},"s":{"a":{"df":0,"docs":{},"g":{"df":2,"docs":{"11":{"tf":1.0},"64":{"tf":1.0}}}},"df":0,"docs":{}}},"t":{"a":{"d":{"a":{"df":0,"docs":{},"t":{"a":{"df":1,"docs":{"33":{"tf":1.7320508075688772}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":3,"docs":{"0":{"tf":1.0},"14":{"tf":1.0},"70":{"tf":1.0}}}}}},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"c":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":1,"docs":{"65":{"tf":1.0}}}}},"df":0,"docs":{}}}},"s":{"df":0,"docs":{},"s":{"df":2,"docs":{"18":{"tf":1.4142135623730951},"72":{"tf":1.4142135623730951}}},"t":{"a":{"df":0,"docs":{},"k":{"df":1,"docs":{"65":{"tf":1.0}}}},"df":0,"docs":{}}},"x":{"df":1,"docs":{"52":{"tf":1.0}}}},"l":{"df":0,"docs":{},"o":{"a":{"d":{"df":1,"docs":{"40":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}},"o":{"d":{"df":0,"docs":{},"e":{"df":2,"docs":{"18":{"tf":1.4142135623730951},"50":{"tf":1.0}},"l":{"df":5,"docs":{"0":{"tf":1.0},"43":{"tf":1.4142135623730951},"49":{"tf":1.4142135623730951},"52":{"tf":1.0},"65":{"tf":1.0}}}},"u":{"df":0,"docs":{},"l":{"df":2,"docs":{"64":{"tf":1.0},"9":{"tf":1.0}}}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"72":{"tf":1.0}}}}}},"r":{"df":0,"docs":{},"e":{"df":10,"docs":{"11":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"2":{"tf":1.0},"33":{"tf":1.0},"5":{"tf":1.7320508075688772},"53":{"tf":1.0},"55":{"tf":1.0},"75":{"tf":1.4142135623730951},"80":{"tf":1.7320508075688772}}}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":3,"docs":{"24":{"tf":1.0},"75":{"tf":1.0},"92":{"tf":1.0}}}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":1,"docs":{"91":{"tf":1.0}}}}},"v":{"df":0,"docs":{},"e":{"df":1,"docs":{"75":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"z":{"df":0,"docs":{},"e":{"df":1,"docs":{"40":{"tf":1.4142135623730951}}}}},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":1,"docs":{"40":{"tf":1.0}}}}}}},"u":{"c":{"df":0,"docs":{},"h":{"df":4,"docs":{"4":{"tf":1.0},"53":{"tf":1.0},"75":{"tf":1.0},"80":{"tf":1.4142135623730951}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":2,"docs":{"5":{"tf":1.0},"52":{"tf":1.0}}}}}}},"s":{"df":0,"docs":{},"l":{"df":4,"docs":{"7":{"tf":1.0},"71":{"tf":1.0},"81":{"tf":1.0},"83":{"tf":1.7320508075688772}}}}}},"n":{"a":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":4,"docs":{"32":{"tf":1.0},"5":{"tf":1.4142135623730951},"62":{"tf":1.0},"64":{"tf":1.0}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":2,"docs":{"4":{"tf":1.0},"75":{"tf":1.4142135623730951}}}},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"52":{"tf":1.0}}}}}},"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"91":{"tf":1.0}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"e":{"d":{"df":9,"docs":{"18":{"tf":1.7320508075688772},"33":{"tf":1.4142135623730951},"39":{"tf":1.0},"52":{"tf":1.0},"62":{"tf":1.4142135623730951},"64":{"tf":1.0},"71":{"tf":1.0},"75":{"tf":1.0},"91":{"tf":1.0}}},"df":0,"docs":{}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"18":{"tf":1.0},"79":{"tf":1.0}}}}},"w":{"df":3,"docs":{"43":{"tf":1.0},"62":{"tf":1.0},"77":{"tf":1.0}}}},"i":{"c":{"df":0,"docs":{},"e":{"df":1,"docs":{"19":{"tf":1.0}}}},"df":0,"docs":{}},"o":{"d":{"df":0,"docs":{},"e":{".":{"df":0,"docs":{},"j":{"df":3,"docs":{"19":{"tf":1.0},"81":{"tf":1.0},"9":{"tf":1.0}}}},"df":2,"docs":{"53":{"tf":1.4142135623730951},"80":{"tf":1.0}}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"5":{"tf":1.0}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"n":{"df":6,"docs":{"18":{"tf":1.0},"62":{"tf":1.0},"64":{"tf":1.0},"68":{"tf":1.0},"70":{"tf":1.0},"71":{"tf":1.0}}},"t":{"a":{"b":{"df":0,"docs":{},"l":{"df":2,"docs":{"0":{"tf":1.0},"91":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"e":{"df":8,"docs":{"18":{"tf":1.4142135623730951},"19":{"tf":1.0},"33":{"tf":1.0},"39":{"tf":1.0},"52":{"tf":1.0},"74":{"tf":1.0},"75":{"tf":1.0},"79":{"tf":1.0}},"w":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"df":1,"docs":{"39":{"tf":1.0}}}}}}}}}}},"p":{"df":0,"docs":{},"m":{"df":2,"docs":{"19":{"tf":1.7320508075688772},"9":{"tf":1.0}}},"x":{"df":1,"docs":{"19":{"tf":1.0}}}},"u":{"a":{"df":0,"docs":{},"n":{"c":{"df":2,"docs":{"65":{"tf":1.0},"80":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"75":{"tf":1.0}}}}}}},"m":{"b":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"64":{"tf":1.0},"75":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"27":{"tf":1.4142135623730951}}}}},"t":{"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":2,"docs":{"43":{"tf":1.0},"53":{"tf":1.0}}}}}}}}},"o":{"(":{"df":0,"docs":{},"n":{"df":1,"docs":{"75":{"tf":1.0}}}},"b":{"df":0,"docs":{},"j":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":8,"docs":{"16":{"tf":1.0},"18":{"tf":1.0},"25":{"tf":1.0},"27":{"tf":1.0},"28":{"tf":1.4142135623730951},"31":{"tf":1.0},"67":{"tf":1.4142135623730951},"74":{"tf":1.0}}}},"df":0,"docs":{}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":4,"docs":{"0":{"tf":1.0},"3":{"tf":1.0},"34":{"tf":1.0},"79":{"tf":1.4142135623730951}}}}}},"t":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":2,"docs":{"81":{"tf":1.0},"82":{"tf":1.0}}}}},"df":0,"docs":{}},"v":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":1,"docs":{"64":{"tf":1.0}}}}}}},"df":3,"docs":{"12":{"tf":1.0},"19":{"tf":1.0},"29":{"tf":1.0}},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":3,"docs":{"4":{"tf":1.0},"49":{"tf":1.0},"70":{"tf":1.0}}}},"i":{"c":{"df":0,"docs":{},"i":{"df":3,"docs":{"18":{"tf":1.0},"64":{"tf":1.0},"68":{"tf":1.0}}}},"df":0,"docs":{}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":4,"docs":{"39":{"tf":1.4142135623730951},"40":{"tf":1.0},"41":{"tf":1.0},"57":{"tf":1.0}}}}}}},"k":{"(":{"0":{"df":1,"docs":{"57":{"tf":1.4142135623730951}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":1,"docs":{"57":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}}}}}}}}},"df":0,"docs":{}}}}},"df":1,"docs":{"57":{"tf":1.4142135623730951}}},"n":{"df":5,"docs":{"15":{"tf":1.0},"33":{"tf":1.0},"65":{"tf":1.0},"75":{"tf":1.0},"91":{"tf":1.0}},"w":{"a":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"85":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"p":{"c":{"df":0,"docs":{},"o":{"d":{"df":3,"docs":{"43":{"tf":1.0},"49":{"tf":1.0},"87":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":2,"docs":{"59":{"tf":1.0},"63":{"tf":1.0}}},"r":{"df":3,"docs":{"40":{"tf":1.0},"68":{"tf":1.0},"7":{"tf":1.0}}}},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":1,"docs":{"72":{"tf":1.4142135623730951}}}}}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":12,"docs":{"12":{"tf":3.3166247903554},"16":{"tf":1.0},"18":{"tf":1.7320508075688772},"28":{"tf":1.0},"29":{"tf":1.0},"4":{"tf":1.0},"40":{"tf":1.0},"52":{"tf":1.0},"67":{"tf":1.0},"70":{"tf":1.0},"72":{"tf":2.23606797749979},"92":{"tf":1.4142135623730951}},"i":{"df":0,"docs":{},"z":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"66":{"tf":1.0}}}}}}},"o":{"df":0,"docs":{},"n":{"df":2,"docs":{"11":{"tf":1.4142135623730951},"19":{"tf":1.4142135623730951}}}}}}},"r":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"51":{"tf":1.0},"75":{"tf":1.4142135623730951}}}}},"df":0,"docs":{},"g":{"a":{"df":0,"docs":{},"n":{"df":1,"docs":{"62":{"tf":1.0}}}},"df":0,"docs":{}},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"o":{"df":0,"docs":{},"g":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"72":{"tf":1.0}}}}}}}}},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"w":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":1,"docs":{"18":{"tf":1.0}}}}}}}}},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":2,"docs":{"34":{"tf":1.0},"39":{"tf":1.0}}}}},"t":{"_":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"57":{"tf":1.0}}}}}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"df":1,"docs":{"79":{"tf":1.4142135623730951}}}}},"d":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"23":{"tf":1.0}}}},"df":0,"docs":{}},"df":1,"docs":{"88":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"64":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"f":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"40":{"tf":1.0}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"g":{"a":{"df":1,"docs":{"39":{"tf":1.0}}},"df":0,"docs":{}}}},"p":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":6,"docs":{"16":{"tf":1.0},"17":{"tf":1.0},"31":{"tf":1.0},"32":{"tf":2.23606797749979},"33":{"tf":3.0},"55":{"tf":1.0}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":2,"docs":{"32":{"tf":1.4142135623730951},"33":{"tf":1.0}}}},"df":0,"docs":{}}}}}}}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"r":{"c":{"df":0,"docs":{},"h":{"df":2,"docs":{"5":{"tf":1.0},"67":{"tf":1.0}}}},"df":0,"docs":{}}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"df":1,"docs":{"75":{"tf":1.0}}}}},"df":2,"docs":{"68":{"tf":1.0},"91":{"tf":1.0}},"f":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":1,"docs":{"70":{"tf":1.0}}}}}},"h":{"df":0,"docs":{},"e":{"a":{"d":{"df":1,"docs":{"75":{"tf":1.7320508075688772}}},"df":0,"docs":{}},"df":0,"docs":{}}},"r":{"df":0,"docs":{},"i":{"d":{"df":1,"docs":{"51":{"tf":1.0}}},"df":0,"docs":{}}},"v":{"df":0,"docs":{},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"df":1,"docs":{"92":{"tf":1.0}}}}}}}}},"z":{"df":1,"docs":{"12":{"tf":1.0}}}},"p":{"a":{"c":{"df":0,"docs":{},"k":{"a":{"df":0,"docs":{},"g":{"df":3,"docs":{"19":{"tf":1.7320508075688772},"77":{"tf":1.0},"9":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"r":{"df":1,"docs":{"80":{"tf":1.0}}}},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":12,"docs":{"0":{"tf":1.7320508075688772},"34":{"tf":1.0},"37":{"tf":1.0},"41":{"tf":1.0},"46":{"tf":1.0},"53":{"tf":1.0},"55":{"tf":1.0},"73":{"tf":1.4142135623730951},"75":{"tf":1.0},"76":{"tf":1.7320508075688772},"79":{"tf":1.4142135623730951},"80":{"tf":1.0}}}}}},"n":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"64":{"tf":1.0}}},"df":0,"docs":{}}},"r":{"a":{"c":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"91":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"64":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"21":{"tf":1.4142135623730951}}},"y":{"/":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"c":{"@":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"19":{"tf":1.0}}}}}}},"df":0,"docs":{}}},"df":1,"docs":{"19":{"tf":1.0}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"5":{"tf":1.0},"69":{"tf":1.4142135623730951}}}}},"t":{"df":1,"docs":{"62":{"tf":1.0}},"i":{"df":2,"docs":{"20":{"tf":1.0},"64":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"s":{"df":2,"docs":{"63":{"tf":1.4142135623730951},"75":{"tf":1.0}}}},"t":{"df":0,"docs":{},"h":{"/":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"/":{"df":0,"docs":{},"m":{"df":0,"docs":{},"y":{"/":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{".":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":1,"docs":{"32":{"tf":1.0}}}}}},"1":{".":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":1,"docs":{"33":{"tf":1.0}}}}}},"df":0,"docs":{}},"2":{".":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":1,"docs":{"33":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"=":{"/":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"/":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"/":{"df":0,"docs":{},"g":{"df":0,"docs":{},"o":{"df":1,"docs":{"77":{"tf":1.0}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":3,"docs":{"15":{"tf":1.4142135623730951},"64":{"tf":1.0},"77":{"tf":1.0}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":1,"docs":{"52":{"tf":1.0}}}}}}}},"c":{"df":1,"docs":{"48":{"tf":1.0}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"m":{"df":3,"docs":{"12":{"tf":1.0},"66":{"tf":1.0},"88":{"tf":1.0}}}}}}}},"h":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"df":1,"docs":{"78":{"tf":1.0}}}}}}}}}}},"i":{"df":0,"docs":{},"e":{"c":{"df":1,"docs":{"52":{"tf":1.0}}},"df":0,"docs":{}},"n":{"df":1,"docs":{"62":{"tf":1.0}}},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":3,"docs":{"50":{"tf":1.0},"61":{"tf":1.0},"92":{"tf":1.0}}}}}}}},"l":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"m":{"df":4,"docs":{"68":{"tf":1.0},"7":{"tf":1.0},"71":{"tf":1.0},"91":{"tf":1.0}}}}}}}},"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"s":{"df":8,"docs":{"10":{"tf":1.0},"11":{"tf":1.0},"61":{"tf":1.0},"62":{"tf":1.7320508075688772},"64":{"tf":1.4142135623730951},"65":{"tf":1.0},"7":{"tf":1.0},"8":{"tf":1.0}}}},"df":0,"docs":{}}},"o":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"39":{"tf":1.4142135623730951},"43":{"tf":1.4142135623730951}}}}}}},"l":{"a":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{"df":1,"docs":{"4":{"tf":1.0}}}}},"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"i":{"df":1,"docs":{"65":{"tf":1.0}}}},"df":0,"docs":{}},"k":{"a":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":6,"docs":{"2":{"tf":1.4142135623730951},"4":{"tf":1.0},"49":{"tf":1.0},"52":{"tf":1.0},"73":{"tf":1.0},"76":{"tf":1.0}}}}},"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{"df":7,"docs":{"1":{"tf":1.0},"5":{"tf":1.0},"55":{"tf":1.0},"6":{"tf":1.4142135623730951},"67":{"tf":1.4142135623730951},"73":{"tf":1.0},"82":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}}},"p":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"r":{"df":2,"docs":{"18":{"tf":1.0},"66":{"tf":1.0}}}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"t":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"19":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"65":{"tf":1.0}}}}}}},"s":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"b":{"df":0,"docs":{},"l":{"df":5,"docs":{"13":{"tf":1.0},"14":{"tf":1.0},"62":{"tf":1.4142135623730951},"78":{"tf":1.7320508075688772},"91":{"tf":1.0}}}},"df":0,"docs":{}}},"t":{"df":1,"docs":{"22":{"tf":1.0}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":3,"docs":{"0":{"tf":1.0},"34":{"tf":1.0},"68":{"tf":1.0}}}}}}},"w":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"66":{"tf":1.0},"80":{"tf":1.0}}}}}},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"c":{"df":2,"docs":{"52":{"tf":1.0},"75":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":3,"docs":{"62":{"tf":1.4142135623730951},"63":{"tf":1.7320508075688772},"65":{"tf":1.0}},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"62":{"tf":1.0}}}},"i":{"df":0,"docs":{},"x":{"df":1,"docs":{"62":{"tf":1.4142135623730951}}}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":2,"docs":{"40":{"tf":1.0},"78":{"tf":1.0}}}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":2,"docs":{"68":{"tf":1.0},"70":{"tf":1.0}}}}},"r":{"a":{"df":0,"docs":{},"n":{"d":{"a":{"df":0,"docs":{},"o":{"df":1,"docs":{"47":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"52":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"r":{"df":3,"docs":{"18":{"tf":1.0},"65":{"tf":1.0},"75":{"tf":1.0}},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"92":{"tf":1.0}}}}}}}},"o":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"65":{"tf":1.4142135623730951}}}},"df":1,"docs":{"75":{"tf":1.0}}}}}},"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":7,"docs":{"33":{"tf":1.0},"50":{"tf":1.0},"65":{"tf":1.0},"66":{"tf":1.0},"67":{"tf":1.0},"71":{"tf":1.0},"8":{"tf":1.0}}}}}},"d":{"df":0,"docs":{},"u":{"c":{"df":5,"docs":{"18":{"tf":1.0},"48":{"tf":1.0},"49":{"tf":1.0},"65":{"tf":1.0},"66":{"tf":1.0}},"t":{"df":1,"docs":{"18":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"88":{"tf":1.0}}}}},"g":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"m":{"df":2,"docs":{"52":{"tf":1.0},"91":{"tf":1.0}}}},"df":0,"docs":{}}},"j":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":6,"docs":{"3":{"tf":1.0},"5":{"tf":1.0},"59":{"tf":1.0},"65":{"tf":1.4142135623730951},"82":{"tf":1.0},"91":{"tf":1.0}},"’":{"df":2,"docs":{"60":{"tf":1.0},"92":{"tf":1.0}}}}},"df":0,"docs":{}}},"o":{"df":0,"docs":{},"f":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"z":{"df":1,"docs":{"57":{"tf":2.449489742783178}}}}}},"df":2,"docs":{"52":{"tf":1.0},"65":{"tf":1.0}}}},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"68":{"tf":1.0}}}}}}},"v":{"df":0,"docs":{},"e":{"df":1,"docs":{"79":{"tf":1.0}}},"i":{"d":{"df":8,"docs":{"18":{"tf":2.23606797749979},"52":{"tf":1.0},"56":{"tf":1.0},"64":{"tf":1.7320508075688772},"66":{"tf":1.0},"76":{"tf":1.0},"79":{"tf":1.4142135623730951},"91":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"x":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"75":{"tf":1.0}}}}}}},"u":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"c":{"df":2,"docs":{"51":{"tf":1.4142135623730951},"64":{"tf":1.0}}},"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"df":1,"docs":{"19":{"tf":1.0}}}}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":1,"docs":{"63":{"tf":1.4142135623730951}}}},"r":{"df":0,"docs":{},"g":{"a":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"=":{"6":{"1":{"4":{"4":{"/":{"3":{"1":{"4":{"5":{"7":{"2":{"8":{"df":1,"docs":{"57":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"s":{"df":5,"docs":{"16":{"tf":1.0},"17":{"tf":1.0},"30":{"tf":1.0},"52":{"tf":1.0},"75":{"tf":1.0}}}}}},"s":{"df":0,"docs":{},"h":{"df":1,"docs":{"63":{"tf":1.0}}}}},"v":{"df":0,"docs":{},"m":{"df":24,"docs":{"0":{"tf":1.4142135623730951},"13":{"tf":1.0},"14":{"tf":1.4142135623730951},"16":{"tf":1.0},"18":{"tf":1.0},"24":{"tf":1.0},"25":{"tf":1.0},"27":{"tf":1.0},"28":{"tf":1.0},"35":{"tf":1.0},"39":{"tf":1.0},"4":{"tf":1.4142135623730951},"48":{"tf":1.0},"52":{"tf":1.0},"55":{"tf":1.0},"70":{"tf":1.0},"71":{"tf":1.0},"72":{"tf":1.0},"73":{"tf":1.4142135623730951},"74":{"tf":1.0},"75":{"tf":2.6457513110645907},"79":{"tf":1.4142135623730951},"91":{"tf":1.0},"92":{"tf":1.0}}}},"y":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"52":{"tf":1.0}}}}}}}},"q":{"df":0,"docs":{},"u":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"64":{"tf":1.0}}}},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"59":{"tf":1.0}}}}}}},"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"k":{"df":1,"docs":{"60":{"tf":1.0}}}},"df":0,"docs":{}}}},"r":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":1,"docs":{"18":{"tf":1.4142135623730951}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"65":{"tf":1.0}}}},"df":0,"docs":{}}}}},"w":{"df":1,"docs":{"18":{"tf":1.0}}}},"df":0,"docs":{},"e":{"a":{"d":{"a":{"b":{"df":0,"docs":{},"l":{"df":2,"docs":{"61":{"tf":1.0},"64":{"tf":1.0}}}},"df":0,"docs":{}},"df":5,"docs":{"1":{"tf":1.0},"34":{"tf":1.0},"40":{"tf":1.0},"61":{"tf":1.0},"65":{"tf":1.0}},"m":{"df":0,"docs":{},"e":{".":{"df":0,"docs":{},"m":{"d":{"df":2,"docs":{"10":{"tf":1.0},"60":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"z":{"df":2,"docs":{"72":{"tf":1.0},"91":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":7,"docs":{"18":{"tf":1.0},"32":{"tf":1.0},"43":{"tf":1.0},"52":{"tf":1.0},"69":{"tf":1.0},"70":{"tf":1.0},"91":{"tf":1.0}}}}}},"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":1,"docs":{"39":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"m":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"d":{"df":2,"docs":{"69":{"tf":1.0},"88":{"tf":1.0}}},"df":0,"docs":{}}}}}}},"d":{"df":0,"docs":{},"u":{"c":{"df":1,"docs":{"75":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"f":{"_":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"57":{"tf":2.449489742783178}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":7,"docs":{"39":{"tf":1.0},"4":{"tf":1.0},"6":{"tf":1.0},"60":{"tf":1.0},"78":{"tf":1.0},"79":{"tf":1.0},"8":{"tf":1.0}}}}},"g":{"a":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"50":{"tf":1.0}},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"18":{"tf":1.0}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":2,"docs":{"13":{"tf":1.0},"75":{"tf":1.4142135623730951}}}}},"u":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"52":{"tf":1.0}}}},"df":0,"docs":{}},"r":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"65":{"tf":1.0}}}}}},"df":0,"docs":{}}}},"j":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"65":{"tf":1.0}}}},"df":0,"docs":{}}},"l":{"a":{"df":0,"docs":{},"t":{"df":3,"docs":{"24":{"tf":1.0},"40":{"tf":1.0},"49":{"tf":1.4142135623730951}}}},"df":1,"docs":{"18":{"tf":1.0}},"e":{"a":{"df":0,"docs":{},"s":{"df":4,"docs":{"68":{"tf":1.4142135623730951},"7":{"tf":1.4142135623730951},"71":{"tf":1.4142135623730951},"92":{"tf":1.7320508075688772}}}},"df":0,"docs":{}},"i":{"df":2,"docs":{"66":{"tf":1.0},"92":{"tf":1.0}}},"o":{"c":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"74":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"x":{".":{"df":0,"docs":{},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"k":{"a":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{".":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":1,"docs":{"23":{"tf":1.0}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":1,"docs":{"23":{"tf":1.4142135623730951}}}},"o":{"df":0,"docs":{},"v":{"df":3,"docs":{"49":{"tf":1.0},"75":{"tf":1.0},"79":{"tf":1.0}}}}},"p":{"df":0,"docs":{},"l":{"a":{"c":{"df":1,"docs":{"90":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":1,"docs":{"80":{"tf":1.0}}}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":2,"docs":{"54":{"tf":1.0},"63":{"tf":1.0}}}}}}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":1,"docs":{"52":{"tf":1.0}},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":2,"docs":{"66":{"tf":1.0},"67":{"tf":1.0}}}}}}},"o":{"d":{"df":0,"docs":{},"u":{"c":{"df":1,"docs":{"68":{"tf":1.7320508075688772}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"q":{"df":0,"docs":{},"u":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":4,"docs":{"18":{"tf":1.0},"32":{"tf":1.0},"33":{"tf":1.7320508075688772},"63":{"tf":1.7320508075688772}}}}},"i":{"df":0,"docs":{},"r":{"df":11,"docs":{"18":{"tf":1.0},"53":{"tf":1.0},"54":{"tf":1.0},"6":{"tf":1.0},"64":{"tf":1.0},"65":{"tf":1.0},"71":{"tf":1.0},"74":{"tf":1.0},"75":{"tf":1.0},"77":{"tf":1.0},"82":{"tf":1.0}}}}}},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"c":{".":{"df":0,"docs":{},"j":{"df":1,"docs":{"81":{"tf":1.0}}}},"df":28,"docs":{"10":{"tf":1.0},"11":{"tf":1.7320508075688772},"12":{"tf":1.0},"18":{"tf":2.0},"19":{"tf":1.0},"20":{"tf":1.0},"21":{"tf":1.0},"22":{"tf":1.0},"23":{"tf":1.4142135623730951},"26":{"tf":1.0},"27":{"tf":1.4142135623730951},"29":{"tf":1.0},"32":{"tf":1.0},"33":{"tf":1.4142135623730951},"4":{"tf":2.0},"5":{"tf":2.0},"50":{"tf":1.0},"6":{"tf":1.0},"61":{"tf":1.4142135623730951},"67":{"tf":1.7320508075688772},"68":{"tf":1.4142135623730951},"7":{"tf":1.4142135623730951},"71":{"tf":1.0},"8":{"tf":1.0},"82":{"tf":1.0},"88":{"tf":1.0},"90":{"tf":1.4142135623730951},"92":{"tf":1.0}}},"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"18":{"tf":1.0}}}},"v":{"df":1,"docs":{"18":{"tf":1.0}}}},"u":{"df":0,"docs":{},"r":{"c":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}}}},"t":{"df":1,"docs":{"32":{"tf":1.0}},"r":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"t":{"df":3,"docs":{"41":{"tf":1.0},"46":{"tf":1.0},"89":{"tf":1.0}}}},"df":0,"docs":{}}}},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":2,"docs":{"69":{"tf":1.0},"79":{"tf":1.7320508075688772}}}}}},"t":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"91":{"tf":1.0}}}}},"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"d":{"a":{"df":0,"docs":{},"t":{"a":{"df":1,"docs":{"46":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":7,"docs":{"35":{"tf":1.0},"38":{"tf":1.0},"41":{"tf":1.0},"44":{"tf":1.0},"45":{"tf":1.0},"46":{"tf":1.0},"51":{"tf":2.449489742783178}}}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":4,"docs":{"13":{"tf":1.0},"14":{"tf":1.0},"46":{"tf":1.0},"57":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"df":1,"docs":{"65":{"tf":1.0}}}},"v":{"df":37,"docs":{"0":{"tf":1.7320508075688772},"10":{"tf":1.0},"24":{"tf":1.0},"3":{"tf":1.0},"34":{"tf":1.0},"37":{"tf":1.0},"40":{"tf":1.0},"41":{"tf":1.0},"43":{"tf":2.23606797749979},"46":{"tf":1.0},"5":{"tf":2.0},"50":{"tf":1.0},"52":{"tf":1.0},"53":{"tf":1.7320508075688772},"54":{"tf":1.7320508075688772},"55":{"tf":1.4142135623730951},"56":{"tf":1.0},"57":{"tf":1.0},"58":{"tf":1.0},"59":{"tf":1.0},"6":{"tf":1.0},"62":{"tf":1.4142135623730951},"65":{"tf":1.0},"66":{"tf":1.4142135623730951},"67":{"tf":1.0},"68":{"tf":1.0},"69":{"tf":2.23606797749979},"71":{"tf":1.0},"73":{"tf":1.7320508075688772},"75":{"tf":1.0},"76":{"tf":2.23606797749979},"77":{"tf":1.0},"79":{"tf":2.8284271247461903},"80":{"tf":1.7320508075688772},"82":{"tf":1.7320508075688772},"9":{"tf":1.4142135623730951},"91":{"tf":1.4142135623730951}},"e":{"_":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{"_":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"x":{"=":{"$":{"df":0,"docs":{},"{":{"df":0,"docs":{},"p":{"df":0,"docs":{},"w":{"d":{"df":0,"docs":{},"}":{"/":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"82":{"tf":1.0}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":1,"docs":{"82":{"tf":1.0}}}}}}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"91":{"tf":1.0}}}}}}},"w":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"91":{"tf":1.0}}}}}}},"i":{"df":0,"docs":{},"s":{"c":{"df":5,"docs":{"52":{"tf":1.0},"66":{"tf":1.0},"67":{"tf":1.0},"72":{"tf":1.0},"75":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"o":{"a":{"d":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"p":{"df":3,"docs":{"52":{"tf":1.0},"91":{"tf":1.0},"92":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"32":{"tf":1.0}}}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":0,"docs":{},"p":{"df":1,"docs":{"49":{"tf":1.4142135623730951}}}}}},"o":{"df":0,"docs":{},"m":{"df":1,"docs":{"79":{"tf":1.0}}},"t":{"df":1,"docs":{"54":{"tf":1.0}}}},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":1,"docs":{"92":{"tf":1.0}}}}}},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":4,"docs":{"0":{"tf":1.0},"37":{"tf":1.4142135623730951},"61":{"tf":1.0},"63":{"tf":1.0}}}},"n":{"df":10,"docs":{"0":{"tf":1.0},"3":{"tf":1.0},"51":{"tf":1.0},"53":{"tf":1.4142135623730951},"56":{"tf":1.0},"61":{"tf":1.4142135623730951},"62":{"tf":1.0},"77":{"tf":1.0},"81":{"tf":1.0},"88":{"tf":1.0}},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":6,"docs":{"53":{"tf":1.4142135623730951},"54":{"tf":1.4142135623730951},"56":{"tf":1.0},"57":{"tf":1.0},"79":{"tf":2.449489742783178},"80":{"tf":1.4142135623730951}}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":12,"docs":{"0":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"35":{"tf":2.0},"40":{"tf":1.0},"43":{"tf":1.4142135623730951},"53":{"tf":1.0},"55":{"tf":1.4142135623730951},"73":{"tf":1.0},"76":{"tf":1.7320508075688772},"79":{"tf":1.0},"80":{"tf":1.0}},"e":{":":{":":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":1,"docs":{"57":{"tf":1.7320508075688772}},"i":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{":":{":":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"c":{"df":1,"docs":{"57":{"tf":2.449489742783178}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"s":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"g":{"=":{"df":0,"docs":{},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"k":{"a":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{"=":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"c":{"df":1,"docs":{"55":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}},"r":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"=":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"c":{"df":2,"docs":{"55":{"tf":1.0},"57":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}}}},"df":1,"docs":{"55":{"tf":1.0}}}}}},"df":7,"docs":{"52":{"tf":2.8284271247461903},"54":{"tf":1.0},"62":{"tf":1.7320508075688772},"64":{"tf":1.0},"71":{"tf":1.0},"83":{"tf":1.4142135623730951},"91":{"tf":1.0}}}}},"v":{"6":{"4":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"a":{"c":{"b":{"df":1,"docs":{"71":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"s":{"a":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":2,"docs":{"52":{"tf":1.0},"92":{"tf":1.0}}}},"m":{"df":0,"docs":{},"e":{"df":7,"docs":{"18":{"tf":1.4142135623730951},"52":{"tf":1.0},"64":{"tf":1.0},"68":{"tf":1.0},"75":{"tf":1.0},"80":{"tf":1.0},"87":{"tf":1.0}}}},"n":{"d":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"x":{"df":3,"docs":{"53":{"tf":1.0},"75":{"tf":1.0},"79":{"tf":1.0}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"v":{"df":0,"docs":{},"e":{"df":1,"docs":{"43":{"tf":1.0}}}}},"c":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":1,"docs":{"91":{"tf":1.4142135623730951}}}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":3,"docs":{"52":{"tf":1.0},"71":{"tf":1.0},"82":{"tf":1.0}}}}}}},"d":{"df":0,"docs":{},"k":{"df":1,"docs":{"52":{"tf":1.4142135623730951}}}},"df":1,"docs":{"12":{"tf":1.0}},"e":{"a":{"df":0,"docs":{},"l":{"_":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"(":{"df":0,"docs":{},"f":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"g":{"df":1,"docs":{"57":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}},"m":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"52":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"43":{"tf":1.0}}}}}}}}}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"d":{"df":2,"docs":{"32":{"tf":1.0},"92":{"tf":1.0}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":2,"docs":{"0":{"tf":1.0},"34":{"tf":1.4142135623730951}}}}}},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"65":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"d":{"df":1,"docs":{"75":{"tf":1.0}}},"df":8,"docs":{"11":{"tf":1.0},"22":{"tf":1.0},"40":{"tf":1.0},"52":{"tf":1.0},"54":{"tf":1.0},"69":{"tf":1.0},"86":{"tf":1.0},"87":{"tf":1.0}}},"l":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":2,"docs":{"31":{"tf":1.0},"33":{"tf":2.0}},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"33":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}}},"m":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":5,"docs":{"0":{"tf":1.0},"64":{"tf":1.0},"72":{"tf":1.0},"78":{"tf":1.0},"79":{"tf":1.0}}}}},"df":0,"docs":{}},"n":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"65":{"tf":1.0}}}}},"t":{"df":1,"docs":{"80":{"tf":1.0}}}},"t":{"df":10,"docs":{"12":{"tf":1.0},"18":{"tf":1.0},"25":{"tf":1.0},"27":{"tf":1.0},"28":{"tf":1.0},"29":{"tf":1.0},"32":{"tf":1.4142135623730951},"33":{"tf":1.0},"70":{"tf":1.0},"79":{"tf":1.4142135623730951}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"s":{".":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"u":{"df":1,"docs":{"30":{"tf":1.0}}}}}},"df":0,"docs":{}}}}},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"28":{"tf":1.4142135623730951}},"i":{"df":0,"docs":{},"z":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{".":{"df":0,"docs":{},"m":{"df":0,"docs":{},"o":{"d":{"df":1,"docs":{"29":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}}}},"u":{"df":0,"docs":{},"t":{"df":0,"docs":{},"p":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"31":{"tf":1.0}}}},"df":0,"docs":{}}}}}}}}}}},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"k":{"a":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{".":{"d":{"df":0,"docs":{},"e":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"m":{"df":1,"docs":{"26":{"tf":1.0}}}}}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"y":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{".":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"s":{"df":1,"docs":{"27":{"tf":1.0}}}}},"df":0,"docs":{}}},"s":{"df":0,"docs":{},"t":{"a":{"c":{"df":0,"docs":{},"k":{"df":0,"docs":{},"s":{"df":1,"docs":{"27":{"tf":1.0}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":1,"docs":{"27":{"tf":1.0}}}}}}}},"df":0,"docs":{}}}}}}}},"df":1,"docs":{"25":{"tf":1.0}}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}}}}}},"h":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":1,"docs":{"67":{"tf":1.4142135623730951}}}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":1,"docs":{"75":{"tf":1.0}}}},"w":{"df":2,"docs":{"65":{"tf":1.0},"75":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"n":{"df":1,"docs":{"65":{"tf":1.0}},"i":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"c":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":2,"docs":{"91":{"tf":1.0},"92":{"tf":1.0}}}}}}},"df":2,"docs":{"72":{"tf":1.0},"91":{"tf":1.0}}},"df":0,"docs":{}}}}}},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"r":{"df":4,"docs":{"18":{"tf":1.0},"33":{"tf":1.0},"70":{"tf":1.0},"75":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"90":{"tf":1.0}}}}}},"df":0,"docs":{}}},"p":{"df":0,"docs":{},"l":{"df":4,"docs":{"18":{"tf":1.0},"69":{"tf":1.0},"77":{"tf":1.0},"79":{"tf":1.0}},"i":{"df":1,"docs":{"79":{"tf":1.0}},"f":{"df":0,"docs":{},"i":{"df":2,"docs":{"18":{"tf":1.0},"79":{"tf":1.0}}}}}}}},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"l":{"df":6,"docs":{"29":{"tf":1.0},"35":{"tf":1.0},"5":{"tf":1.4142135623730951},"53":{"tf":1.0},"75":{"tf":1.0},"91":{"tf":1.0}}}}},"t":{"df":1,"docs":{"75":{"tf":1.0}}},"z":{"df":0,"docs":{},"e":{"df":15,"docs":{"0":{"tf":1.4142135623730951},"12":{"tf":1.7320508075688772},"13":{"tf":2.449489742783178},"14":{"tf":2.449489742783178},"27":{"tf":2.0},"35":{"tf":1.4142135623730951},"39":{"tf":1.7320508075688772},"40":{"tf":1.0},"41":{"tf":1.0},"43":{"tf":1.0},"45":{"tf":1.0},"46":{"tf":1.0},"70":{"tf":1.4142135623730951},"89":{"tf":1.4142135623730951},"92":{"tf":1.0}}}}},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":1,"docs":{"65":{"tf":1.4142135623730951}}},"w":{"df":1,"docs":{"75":{"tf":1.7320508075688772}},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"75":{"tf":1.0}}}}}}},"m":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":4,"docs":{"13":{"tf":1.0},"14":{"tf":1.0},"50":{"tf":1.0},"52":{"tf":1.0}}}},"r":{"df":0,"docs":{},"t":{"df":3,"docs":{"4":{"tf":1.0},"66":{"tf":1.0},"75":{"tf":1.0}}}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"f":{"df":0,"docs":{},"t":{"df":0,"docs":{},"w":{"a":{"df":0,"docs":{},"r":{"df":3,"docs":{"52":{"tf":1.0},"59":{"tf":1.0},"65":{"tf":1.0}}}},"df":0,"docs":{}}}},"l":{"c":{"df":19,"docs":{"11":{"tf":1.0},"15":{"tf":2.0},"18":{"tf":2.23606797749979},"24":{"tf":1.0},"33":{"tf":1.0},"39":{"tf":1.0},"50":{"tf":1.7320508075688772},"6":{"tf":1.0},"66":{"tf":1.4142135623730951},"67":{"tf":1.0},"68":{"tf":1.4142135623730951},"72":{"tf":1.4142135623730951},"78":{"tf":1.0},"79":{"tf":1.0},"8":{"tf":1.4142135623730951},"85":{"tf":1.0},"88":{"tf":1.0},"90":{"tf":1.4142135623730951},"92":{"tf":1.0}}},"df":0,"docs":{},"e":{"df":1,"docs":{"65":{"tf":1.0}}},"i":{"d":{"df":25,"docs":{"0":{"tf":1.4142135623730951},"1":{"tf":1.4142135623730951},"18":{"tf":2.23606797749979},"21":{"tf":1.4142135623730951},"22":{"tf":1.0},"3":{"tf":1.0},"34":{"tf":1.4142135623730951},"36":{"tf":1.4142135623730951},"39":{"tf":1.0},"4":{"tf":2.0},"43":{"tf":1.0},"5":{"tf":1.0},"52":{"tf":1.7320508075688772},"6":{"tf":1.7320508075688772},"60":{"tf":1.0},"65":{"tf":1.0},"66":{"tf":1.7320508075688772},"67":{"tf":1.4142135623730951},"78":{"tf":1.7320508075688772},"79":{"tf":1.7320508075688772},"8":{"tf":1.0},"85":{"tf":1.0},"88":{"tf":1.0},"91":{"tf":2.0},"92":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"52":{"tf":1.0}}}}},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"52":{"tf":1.0}}},"i":{"df":0,"docs":{},"m":{"df":3,"docs":{"53":{"tf":1.0},"55":{"tf":1.0},"62":{"tf":1.0}}}}},"w":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"75":{"tf":1.0}}}}}}}},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"65":{"tf":1.0}}}}}}},"r":{"c":{"df":10,"docs":{"10":{"tf":1.0},"17":{"tf":1.0},"18":{"tf":1.0},"33":{"tf":1.4142135623730951},"54":{"tf":1.0},"59":{"tf":1.0},"67":{"tf":1.4142135623730951},"77":{"tf":1.0},"82":{"tf":1.0},"92":{"tf":1.0}}},"df":0,"docs":{}}}},"p":{"a":{"c":{"df":0,"docs":{},"e":{"df":1,"docs":{"13":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"df":0,"docs":{},"e":{"c":{"df":2,"docs":{"79":{"tf":1.4142135623730951},"80":{"tf":1.4142135623730951}},"i":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"71":{"tf":1.0}}}},"df":0,"docs":{},"f":{"df":10,"docs":{"25":{"tf":1.0},"27":{"tf":1.0},"28":{"tf":1.0},"32":{"tf":2.449489742783178},"33":{"tf":1.0},"52":{"tf":1.0},"71":{"tf":1.0},"72":{"tf":1.0},"75":{"tf":1.0},"79":{"tf":1.4142135623730951}},"i":{"df":3,"docs":{"15":{"tf":1.0},"16":{"tf":1.0},"30":{"tf":1.0}}}}}},"df":0,"docs":{},"e":{"d":{"df":3,"docs":{"1":{"tf":1.0},"75":{"tf":1.4142135623730951},"91":{"tf":1.0}}},"df":0,"docs":{}}}},"r":{"c":{"/":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"/":{"b":{"a":{"df":0,"docs":{},"r":{".":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{":":{"b":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"18":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":1,"docs":{"18":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"t":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"76":{"tf":1.0}}}},"c":{"df":0,"docs":{},"k":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"z":{"df":1,"docs":{"13":{"tf":1.0}}}}}},"df":6,"docs":{"0":{"tf":1.0},"13":{"tf":2.6457513110645907},"27":{"tf":1.4142135623730951},"72":{"tf":1.0},"78":{"tf":1.0},"79":{"tf":1.0}}}},"df":0,"docs":{},"n":{"d":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"79":{"tf":1.0}}}}},"r":{"d":{"df":4,"docs":{"24":{"tf":1.4142135623730951},"55":{"tf":1.0},"62":{"tf":1.0},"68":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"_":{"df":0,"docs":{},"i":{"d":{"df":1,"docs":{"51":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}}},"df":4,"docs":{"58":{"tf":1.0},"60":{"tf":1.0},"72":{"tf":1.0},"85":{"tf":1.0}},"u":{"df":0,"docs":{},"p":{"df":3,"docs":{"13":{"tf":1.0},"14":{"tf":1.0},"75":{"tf":1.0}}}}}},"t":{"df":0,"docs":{},"e":{"df":5,"docs":{"51":{"tf":1.4142135623730951},"56":{"tf":1.0},"68":{"tf":1.0},"75":{"tf":1.0},"79":{"tf":1.4142135623730951}}},"i":{"c":{"df":4,"docs":{"14":{"tf":1.0},"68":{"tf":1.0},"70":{"tf":1.4142135623730951},"81":{"tf":1.0}}},"df":0,"docs":{}}}},"d":{"df":1,"docs":{"18":{"tf":1.4142135623730951}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"p":{"df":2,"docs":{"67":{"tf":1.0},"79":{"tf":1.0}}}},"i":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":1,"docs":{"18":{"tf":1.0}}}}},"o":{"c":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"65":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"g":{"df":1,"docs":{"79":{"tf":1.0}}}},"df":0,"docs":{}}},"r":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":1,"docs":{"65":{"tf":1.0}},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"w":{"a":{"df":0,"docs":{},"r":{"d":{"df":2,"docs":{"7":{"tf":1.0},"83":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"df":2,"docs":{"77":{"tf":1.4142135623730951},"80":{"tf":1.4142135623730951}}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"52":{"tf":1.0}}}}}}},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":2,"docs":{"18":{"tf":1.0},"64":{"tf":1.0}}}},"p":{"df":1,"docs":{"53":{"tf":1.0}}}},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":3,"docs":{"37":{"tf":1.0},"43":{"tf":1.0},"69":{"tf":1.0}}}}}}},"u":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"18":{"tf":1.0}}}}}},"df":0,"docs":{}}},"u":{"d":{"df":0,"docs":{},"i":{"df":1,"docs":{"0":{"tf":1.0}}}},"df":0,"docs":{}},"y":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":2,"docs":{"64":{"tf":1.0},"65":{"tf":1.0}}}}}},"u":{"b":{"df":0,"docs":{},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":2,"docs":{"63":{"tf":1.4142135623730951},"65":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"18":{"tf":1.0}}}}}}}}},"c":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"20":{"tf":1.0}},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"75":{"tf":1.0}}}}}}}},"df":0,"docs":{},"h":{"df":3,"docs":{"33":{"tf":1.4142135623730951},"52":{"tf":1.0},"64":{"tf":1.0}}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"i":{"df":2,"docs":{"18":{"tf":1.0},"65":{"tf":1.0}}}},"df":0,"docs":{}}}},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"80":{"tf":1.0}}}},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"49":{"tf":1.0}}}}}}},"p":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":4,"docs":{"18":{"tf":1.0},"37":{"tf":1.0},"39":{"tf":1.0},"43":{"tf":1.4142135623730951}}}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":17,"docs":{"18":{"tf":1.0},"21":{"tf":1.0},"23":{"tf":1.0},"28":{"tf":1.0},"32":{"tf":1.0},"33":{"tf":1.0},"4":{"tf":1.0},"40":{"tf":1.0},"42":{"tf":1.0},"52":{"tf":1.4142135623730951},"68":{"tf":1.0},"7":{"tf":1.0},"82":{"tf":1.4142135623730951},"85":{"tf":1.7320508075688772},"86":{"tf":1.4142135623730951},"87":{"tf":1.0},"88":{"tf":1.7320508075688772}}}},"s":{"df":2,"docs":{"18":{"tf":1.0},"57":{"tf":1.0}}}}}},"r":{"df":0,"docs":{},"e":{"df":1,"docs":{"18":{"tf":1.0}}}}},"w":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"80":{"tf":1.0}}}},"df":0,"docs":{}},"y":{"df":1,"docs":{"71":{"tf":1.0}},"m":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":2,"docs":{"18":{"tf":1.4142135623730951},"64":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}},"s":{"c":{"a":{"df":0,"docs":{},"l":{"df":2,"docs":{"57":{"tf":1.0},"76":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":1,"docs":{"7":{"tf":1.0}}}}}}}},"t":{"a":{"df":0,"docs":{},"k":{"df":0,"docs":{},"e":{"df":3,"docs":{"18":{"tf":1.0},"66":{"tf":1.0},"80":{"tf":1.0}}}},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":12,"docs":{"1":{"tf":1.0},"4":{"tf":1.0},"68":{"tf":1.0},"71":{"tf":1.4142135623730951},"72":{"tf":1.7320508075688772},"73":{"tf":1.4142135623730951},"74":{"tf":1.4142135623730951},"75":{"tf":1.0},"76":{"tf":1.0},"78":{"tf":1.0},"81":{"tf":1.0},"82":{"tf":2.23606797749979}}}}}}},"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"h":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"52":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"m":{"df":1,"docs":{"66":{"tf":1.0}},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"g":{"df":1,"docs":{"35":{"tf":1.0}}}}}}}}}},"s":{"df":0,"docs":{},"t":{"df":7,"docs":{"51":{"tf":1.4142135623730951},"61":{"tf":1.4142135623730951},"63":{"tf":1.0},"77":{"tf":2.6457513110645907},"79":{"tf":3.4641016151377544},"80":{"tf":3.0},"82":{"tf":1.0}}}}},"h":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"k":{"df":2,"docs":{"4":{"tf":1.0},"80":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":2,"docs":{"35":{"tf":1.0},"40":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"62":{"tf":1.0}}}},"’":{"df":1,"docs":{"0":{"tf":1.0}}}}}},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":5,"docs":{"11":{"tf":1.0},"18":{"tf":1.0},"5":{"tf":1.0},"62":{"tf":1.0},"64":{"tf":1.4142135623730951}}}},"r":{"d":{"df":2,"docs":{"20":{"tf":1.0},"64":{"tf":1.0}}},"df":0,"docs":{}}},"o":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":2,"docs":{"11":{"tf":1.0},"18":{"tf":1.0}}}},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":1,"docs":{"72":{"tf":1.0}}}}}},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":2,"docs":{"67":{"tf":1.0},"79":{"tf":1.0}}}}}}},"u":{"df":6,"docs":{"18":{"tf":1.0},"32":{"tf":1.0},"40":{"tf":1.0},"43":{"tf":1.0},"72":{"tf":1.0},"80":{"tf":1.0}},"m":{"b":{"df":1,"docs":{"61":{"tf":1.0}}},"df":0,"docs":{}}}},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"52":{"tf":1.0}}}}}}},"m":{"df":0,"docs":{},"e":{"df":7,"docs":{"12":{"tf":1.7320508075688772},"18":{"tf":2.8284271247461903},"41":{"tf":1.0},"46":{"tf":1.0},"48":{"tf":1.0},"49":{"tf":1.0},"75":{"tf":1.4142135623730951}},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"92":{"tf":1.0}}}}}}},"n":{"df":0,"docs":{},"i":{"df":1,"docs":{"80":{"tf":1.0}}}},"p":{"df":3,"docs":{"11":{"tf":1.0},"35":{"tf":1.0},"77":{"tf":1.0}}}},"m":{"df":0,"docs":{},"p":{"/":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"19":{"tf":1.0}}}}}},"df":0,"docs":{}}},"o":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":2,"docs":{"62":{"tf":1.0},"77":{"tf":1.0}}}}}},"o":{"df":0,"docs":{},"l":{"df":7,"docs":{"18":{"tf":1.0},"20":{"tf":1.4142135623730951},"52":{"tf":1.0},"65":{"tf":1.0},"77":{"tf":1.0},"79":{"tf":1.4142135623730951},"89":{"tf":1.0}},"k":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"21":{"tf":1.4142135623730951}}}}}}},"t":{"a":{"df":0,"docs":{},"l":{"df":2,"docs":{"13":{"tf":1.4142135623730951},"14":{"tf":1.0}}}},"df":0,"docs":{}}},"r":{"a":{"c":{"df":0,"docs":{},"e":{"df":2,"docs":{"55":{"tf":2.0},"57":{"tf":3.0}}}},"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"13":{"tf":1.0}},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"52":{"tf":1.0}}}}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"69":{"tf":1.0}}}},"n":{"df":0,"docs":{},"s":{"a":{"c":{"df":0,"docs":{},"t":{"df":2,"docs":{"43":{"tf":1.0},"80":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"t":{"df":7,"docs":{"34":{"tf":1.0},"36":{"tf":1.0},"39":{"tf":1.0},"43":{"tf":1.0},"47":{"tf":1.0},"75":{"tf":1.0},"86":{"tf":1.0}}}},"df":0,"docs":{}}}},"p":{"df":3,"docs":{"0":{"tf":1.0},"39":{"tf":1.0},"40":{"tf":1.0}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"e":{"df":1,"docs":{"69":{"tf":1.0}}}},"i":{"df":2,"docs":{"62":{"tf":1.0},"64":{"tf":1.0}},"v":{"df":0,"docs":{},"i":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"70":{"tf":1.0}}}},"df":0,"docs":{}}}},"u":{"df":0,"docs":{},"e":{"df":2,"docs":{"79":{"tf":1.4142135623730951},"91":{"tf":1.0}}}}},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":1,"docs":{"75":{"tf":1.0}}}}},"w":{"df":0,"docs":{},"o":{"df":3,"docs":{"43":{"tf":1.0},"50":{"tf":1.0},"6":{"tf":1.0}}}},"y":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"75":{"tf":1.0}}},"df":0,"docs":{}}}}},"u":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"51":{"tf":2.0}}}}},"l":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"65":{"tf":1.0}}}}}},"n":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"n":{"df":1,"docs":{"70":{"tf":1.0}}}}}}},"c":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":1,"docs":{"65":{"tf":1.0}}}}}},"df":0,"docs":{}},"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":4,"docs":{"19":{"tf":1.0},"3":{"tf":1.0},"62":{"tf":1.0},"67":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":3,"docs":{"43":{"tf":1.0},"52":{"tf":1.0},"78":{"tf":1.0}}}},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"34":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"d":{"df":1,"docs":{"1":{"tf":1.0}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{},"f":{"a":{"df":0,"docs":{},"v":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"75":{"tf":1.0}}}}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"d":{"df":1,"docs":{"91":{"tf":1.0}}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":1,"docs":{"23":{"tf":1.0}}}}}}}},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"w":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"80":{"tf":1.0}}}},"df":0,"docs":{}}},"t":{"df":1,"docs":{"77":{"tf":1.4142135623730951}},"i":{"df":1,"docs":{"56":{"tf":1.0}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"s":{"df":1,"docs":{"7":{"tf":1.0}}}}}}},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"39":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"k":{"df":3,"docs":{"14":{"tf":1.0},"18":{"tf":1.0},"70":{"tf":1.0}}},"n":{"df":0,"docs":{},"k":{"df":1,"docs":{"18":{"tf":1.7320508075688772}}}}}},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"16":{"tf":1.0}}}}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"63":{"tf":1.0}}}},"r":{"df":0,"docs":{},"u":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"37":{"tf":1.0}}}}}}},"u":{"df":0,"docs":{},"s":{"df":1,"docs":{"40":{"tf":1.0}}}},"w":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"64":{"tf":1.0}}}},"df":0,"docs":{}}}},"p":{"d":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"62":{"tf":1.7320508075688772}}}},"df":0,"docs":{}},"df":3,"docs":{"1":{"tf":1.0},"52":{"tf":1.0},"91":{"tf":1.0}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"m":{"df":2,"docs":{"63":{"tf":1.0},"71":{"tf":1.0}}}},"df":0,"docs":{}}}}}},"s":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"19":{"tf":1.0}}}},"df":0,"docs":{},"g":{"df":4,"docs":{"11":{"tf":1.4142135623730951},"54":{"tf":1.4142135623730951},"57":{"tf":1.0},"70":{"tf":1.0}}}},"df":33,"docs":{"13":{"tf":1.7320508075688772},"14":{"tf":1.4142135623730951},"15":{"tf":1.0},"16":{"tf":1.0},"17":{"tf":1.0},"18":{"tf":2.0},"25":{"tf":1.0},"27":{"tf":1.0},"30":{"tf":1.0},"31":{"tf":1.0},"40":{"tf":1.4142135623730951},"43":{"tf":1.7320508075688772},"48":{"tf":1.4142135623730951},"49":{"tf":1.0},"5":{"tf":1.0},"52":{"tf":1.4142135623730951},"53":{"tf":1.0},"55":{"tf":1.0},"61":{"tf":1.4142135623730951},"64":{"tf":1.7320508075688772},"65":{"tf":1.0},"66":{"tf":1.0},"67":{"tf":1.0},"68":{"tf":1.0},"69":{"tf":1.4142135623730951},"70":{"tf":1.0},"71":{"tf":2.0},"75":{"tf":1.0},"77":{"tf":1.0},"8":{"tf":1.0},"81":{"tf":1.0},"82":{"tf":1.0},"88":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":6,"docs":{"1":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.0},"52":{"tf":1.0},"70":{"tf":1.0},"78":{"tf":1.0}}}},"u":{"a":{"df":0,"docs":{},"l":{"df":3,"docs":{"18":{"tf":1.0},"43":{"tf":1.0},"53":{"tf":1.0}}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":2,"docs":{"79":{"tf":1.0},"80":{"tf":1.0}}}}}},"v":{"0":{".":{"8":{".":{"0":{"df":1,"docs":{"92":{"tf":1.0}}},"df":0,"docs":{}},"df":1,"docs":{"4":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"df":0,"docs":{}},"1":{".":{"0":{".":{"0":{"df":1,"docs":{"92":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"d":{"df":4,"docs":{"12":{"tf":1.0},"39":{"tf":1.0},"48":{"tf":1.0},"75":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"u":{"df":8,"docs":{"13":{"tf":1.4142135623730951},"14":{"tf":1.4142135623730951},"26":{"tf":1.0},"27":{"tf":1.4142135623730951},"29":{"tf":1.0},"39":{"tf":1.0},"45":{"tf":1.0},"47":{"tf":1.0}},"e":{"_":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"d":{"(":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":1,"docs":{"57":{"tf":1.0}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"i":{"a":{"b":{"df":0,"docs":{},"l":{"df":5,"docs":{"13":{"tf":1.0},"51":{"tf":1.4142135623730951},"55":{"tf":1.0},"64":{"tf":1.0},"82":{"tf":1.0}}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"75":{"tf":1.0}}}}},"df":2,"docs":{"12":{"tf":1.0},"40":{"tf":1.0}},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"20":{"tf":1.0}}}}}}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"79":{"tf":1.0}}}}}}},"df":4,"docs":{"52":{"tf":1.0},"66":{"tf":1.0},"67":{"tf":1.0},"75":{"tf":1.4142135623730951}},"e":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"0":{"tf":1.0}}}}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":2,"docs":{"75":{"tf":1.0},"79":{"tf":1.0}},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"52":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":5,"docs":{"23":{"tf":1.0},"61":{"tf":1.0},"68":{"tf":1.0},"85":{"tf":2.0},"88":{"tf":2.0}}}}}}}},"i":{"a":{"df":10,"docs":{"50":{"tf":1.0},"51":{"tf":1.0},"63":{"tf":1.0},"68":{"tf":1.4142135623730951},"7":{"tf":1.0},"70":{"tf":1.0},"71":{"tf":1.0},"73":{"tf":1.0},"80":{"tf":1.0},"82":{"tf":1.4142135623730951}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"df":1,"docs":{"51":{"tf":1.4142135623730951}}}},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"51":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"91":{"tf":1.0}}}},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{".":{"df":0,"docs":{},"r":{"df":1,"docs":{"69":{"tf":1.0}}}},"df":1,"docs":{"69":{"tf":1.4142135623730951}}}}}},"u":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"67":{"tf":1.0}}}},"df":0,"docs":{}}}},"m":{"df":3,"docs":{"43":{"tf":1.0},"52":{"tf":1.4142135623730951},"75":{"tf":1.4142135623730951}}},"s":{"df":3,"docs":{"35":{"tf":1.0},"5":{"tf":1.0},"72":{"tf":1.0}}}},"w":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":3,"docs":{"57":{"tf":1.0},"69":{"tf":1.0},"71":{"tf":1.0}}}},"r":{"df":0,"docs":{},"m":{"df":1,"docs":{"0":{"tf":1.0}}},"n":{"df":6,"docs":{"0":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"18":{"tf":1.0},"41":{"tf":1.0},"43":{"tf":1.0}}}},"s":{"df":0,"docs":{},"m":{"df":4,"docs":{"7":{"tf":1.0},"75":{"tf":2.8284271247461903},"81":{"tf":1.0},"82":{"tf":1.7320508075688772}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"75":{"tf":1.4142135623730951}}}}}}},"y":{"df":3,"docs":{"32":{"tf":1.0},"77":{"tf":1.0},"83":{"tf":1.0}}}},"df":0,"docs":{},"e":{"b":{"3":{"df":1,"docs":{"91":{"tf":1.0}}},"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"b":{"df":0,"docs":{},"m":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"75":{"tf":1.0}}}}}},"df":0,"docs":{}}}}},"df":1,"docs":{"91":{"tf":1.0}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":1,"docs":{"57":{"tf":2.449489742783178}}}}}},"l":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"df":1,"docs":{"0":{"tf":1.4142135623730951}}}}},"df":0,"docs":{},"l":{"df":3,"docs":{"1":{"tf":1.0},"34":{"tf":1.0},"79":{"tf":1.0}}}},"’":{"d":{"df":2,"docs":{"52":{"tf":1.0},"65":{"tf":1.0}}},"df":0,"docs":{}}},"h":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":1,"docs":{"65":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":1,"docs":{"62":{"tf":1.0}}}}},"r":{"df":0,"docs":{},"e":{"a":{"df":1,"docs":{"32":{"tf":1.0}}},"df":0,"docs":{},"v":{"df":1,"docs":{"78":{"tf":1.0}}}}},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"65":{"tf":1.0}}}}}}},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":1,"docs":{"5":{"tf":1.0}}}}}},"i":{"df":0,"docs":{},"e":{"d":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"12":{"tf":1.0}}}}},"df":0,"docs":{}},"l":{"d":{"c":{"a":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"32":{"tf":2.0}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"n":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":2,"docs":{"65":{"tf":1.0},"7":{"tf":1.0}}}}},"df":0,"docs":{}},"s":{"df":0,"docs":{},"h":{"df":1,"docs":{"65":{"tf":1.4142135623730951}}}}},"o":{"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"’":{"df":1,"docs":{"91":{"tf":1.0}}}},"df":0,"docs":{}},"r":{"d":{"df":2,"docs":{"5":{"tf":1.0},"64":{"tf":1.0}}},"df":0,"docs":{},"k":{"df":7,"docs":{"0":{"tf":1.4142135623730951},"18":{"tf":1.4142135623730951},"43":{"tf":1.4142135623730951},"52":{"tf":1.0},"69":{"tf":1.0},"72":{"tf":1.0},"90":{"tf":1.0}},"l":{"df":0,"docs":{},"o":{"a":{"d":{"df":1,"docs":{"75":{"tf":1.7320508075688772}}},"df":0,"docs":{}},"df":0,"docs":{}}},"s":{"df":0,"docs":{},"p":{"a":{"c":{"df":1,"docs":{"62":{"tf":1.7320508075688772}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"l":{"d":{"df":1,"docs":{"11":{"tf":1.0}}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"39":{"tf":1.0}}}},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"w":{"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"11":{"tf":1.0}}}}}}}}}},"r":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"71":{"tf":1.0},"79":{"tf":1.0}}}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":7,"docs":{"40":{"tf":1.0},"41":{"tf":1.0},"46":{"tf":1.0},"64":{"tf":1.0},"75":{"tf":1.0},"79":{"tf":1.0},"88":{"tf":1.0}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":2,"docs":{"52":{"tf":1.4142135623730951},"66":{"tf":1.0}}}}}}}}},"x":{"8":{"6":{"df":1,"docs":{"75":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{},"y":{"df":2,"docs":{"87":{"tf":1.0},"89":{"tf":1.0}}}},"y":{"df":0,"docs":{},"e":{"df":1,"docs":{"86":{"tf":1.0}}},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"f":{"df":1,"docs":{"65":{"tf":1.0}}}}}}},"’":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":1,"docs":{"61":{"tf":1.0}}}}}}},"u":{"df":0,"docs":{},"l":{"df":12,"docs":{"16":{"tf":1.0},"22":{"tf":1.0},"34":{"tf":1.0},"39":{"tf":1.4142135623730951},"5":{"tf":1.0},"50":{"tf":1.0},"6":{"tf":1.0},"66":{"tf":1.0},"67":{"tf":1.4142135623730951},"69":{"tf":1.7320508075688772},"72":{"tf":1.0},"86":{"tf":1.0}}}}},"z":{"df":1,"docs":{"12":{"tf":1.0}},"k":{"df":1,"docs":{"52":{"tf":1.0}}}}}},"breadcrumbs":{"root":{"0":{".":{"8":{".":{"0":{"df":1,"docs":{"85":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":5,"docs":{"12":{"tf":1.0},"41":{"tf":1.0},"51":{"tf":1.4142135623730951},"57":{"tf":3.4641016151377544},"79":{"tf":1.0}}},"1":{".":{"2":{"df":1,"docs":{"18":{"tf":1.0}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"s":{"df":1,"docs":{"14":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"/":{"1":{"0":{"0":{"df":1,"docs":{"75":{"tf":1.0}}},"df":1,"docs":{"75":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"2":{"8":{"df":0,"docs":{},"k":{"b":{"df":3,"docs":{"40":{"tf":1.4142135623730951},"41":{"tf":1.0},"46":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}},"3":{"1":{"0":{"7":{"2":{"df":2,"docs":{"13":{"tf":1.0},"14":{"tf":1.0}}},"df":0,"docs":{}},"8":{"8":{"df":1,"docs":{"57":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"2":{"1":{"6":{"df":1,"docs":{"57":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":5,"docs":{"12":{"tf":1.0},"39":{"tf":1.0},"51":{"tf":1.4142135623730951},"57":{"tf":1.4142135623730951},"75":{"tf":1.0}},"m":{"b":{"df":1,"docs":{"89":{"tf":1.0}}},"df":0,"docs":{}}},"2":{".":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":1,"docs":{"14":{"tf":1.0}}}}}},"4":{"5":{"6":{"6":{"6":{"9":{"df":1,"docs":{"57":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{},"k":{"b":{"df":1,"docs":{"89":{"tf":1.7320508075688772}}},"df":0,"docs":{}}},"5":{"0":{"0":{"0":{"0":{"0":{"0":{"0":{"0":{"0":{"0":{"0":{"0":{"0":{"0":{"df":1,"docs":{"47":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"6":{"df":1,"docs":{"72":{"tf":1.0}}},"df":0,"docs":{}},"9":{"3":{"7":{"6":{"3":{"4":{"df":1,"docs":{"57":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"^":{"3":{"2":{"df":1,"docs":{"39":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":3,"docs":{"12":{"tf":1.0},"32":{"tf":1.0},"75":{"tf":1.0}}},"3":{".":{"0":{"df":1,"docs":{"91":{"tf":1.0}}},"df":0,"docs":{}},"2":{"df":2,"docs":{"39":{"tf":1.0},"45":{"tf":1.0}}},"df":2,"docs":{"12":{"tf":1.0},"18":{"tf":1.4142135623730951}},"f":{"a":{"4":{"df":0,"docs":{},"f":{"2":{"4":{"5":{"df":1,"docs":{"79":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}},"4":{"0":{"8":{"4":{"4":{"8":{"3":{"df":1,"docs":{"57":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"2":{"9":{"4":{"8":{"3":{"6":{"0":{"9":{"6":{"df":1,"docs":{"57":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"5":{"5":{"1":{"0":{"6":{"1":{"5":{"df":1,"docs":{"57":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"6":{"3":{"/":{"6":{"4":{"df":2,"docs":{"0":{"tf":1.0},"37":{"tf":1.7320508075688772}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"4":{"df":1,"docs":{"72":{"tf":1.0}}},"df":0,"docs":{}},"9":{"8":{"5":{"2":{"0":{"9":{"df":1,"docs":{"57":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"d":{"df":1,"docs":{"51":{"tf":1.7320508075688772}}},"df":0,"docs":{}}}}}}}}}},"df":0,"docs":{}}}},"a":{"b":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"52":{"tf":1.0}}}}},"df":0,"docs":{}}},"b":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"df":1,"docs":{"64":{"tf":1.0}}}}}}},"df":0,"docs":{},"i":{"df":1,"docs":{"33":{"tf":1.4142135623730951}}},"o":{"df":0,"docs":{},"v":{"df":3,"docs":{"39":{"tf":1.0},"79":{"tf":1.0},"87":{"tf":1.0}}}}},"c":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":1,"docs":{"59":{"tf":1.0}}}},"s":{"df":0,"docs":{},"s":{"df":2,"docs":{"40":{"tf":1.0},"70":{"tf":1.0}}}}}},"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":1,"docs":{"20":{"tf":1.0}}}}}},"k":{"df":0,"docs":{},"n":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"d":{"df":0,"docs":{},"g":{"df":1,"docs":{"65":{"tf":1.0}}}},"df":0,"docs":{}}}}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"79":{"tf":1.7320508075688772}}}},"v":{"df":2,"docs":{"18":{"tf":1.0},"23":{"tf":1.0}}}},"u":{"a":{"df":0,"docs":{},"l":{"df":4,"docs":{"18":{"tf":1.0},"35":{"tf":1.0},"75":{"tf":1.0},"80":{"tf":1.0}}}},"df":0,"docs":{}}}},"d":{"d":{"df":2,"docs":{"62":{"tf":1.4142135623730951},"64":{"tf":1.0}},"i":{"df":0,"docs":{},"t":{"df":4,"docs":{"24":{"tf":1.0},"4":{"tf":1.0},"64":{"tf":1.4142135623730951},"72":{"tf":1.0}},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"33":{"tf":1.0}}}}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{".":{"c":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"o":{"d":{"df":1,"docs":{"38":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":1,"docs":{"18":{"tf":1.4142135623730951}}}}}}},"df":2,"docs":{"33":{"tf":1.4142135623730951},"62":{"tf":1.0}},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":1,"docs":{"52":{"tf":1.0}}}}},"v":{"a":{"df":0,"docs":{},"n":{"c":{"df":1,"docs":{"12":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"37":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{},"g":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"64":{"tf":1.0}},"s":{"df":0,"docs":{},"t":{"df":3,"docs":{"52":{"tf":1.0},"75":{"tf":1.0},"79":{"tf":1.4142135623730951}}}}}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"12":{"tf":1.4142135623730951}}}}}}}},"i":{"df":3,"docs":{"52":{"tf":1.4142135623730951},"64":{"tf":1.0},"65":{"tf":2.8284271247461903}},"m":{"df":4,"docs":{"11":{"tf":1.0},"78":{"tf":1.0},"90":{"tf":1.0},"92":{"tf":1.0}}}},"l":{"df":0,"docs":{},"g":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"m":{"df":1,"docs":{"52":{"tf":1.0}}}}}}}}},"i":{"a":{"df":0,"docs":{},"s":{"df":1,"docs":{"64":{"tf":1.0}}}},"df":0,"docs":{}},"l":{"df":0,"docs":{},"o":{"c":{"df":1,"docs":{"75":{"tf":1.0}}},"df":0,"docs":{},"w":{"df":7,"docs":{"26":{"tf":1.0},"27":{"tf":1.4142135623730951},"30":{"tf":1.0},"70":{"tf":1.0},"75":{"tf":1.0},"79":{"tf":1.0},"80":{"tf":1.0}}}}},"w":{"a":{"df":0,"docs":{},"y":{"df":10,"docs":{"18":{"tf":1.0},"39":{"tf":1.0},"41":{"tf":1.0},"43":{"tf":1.0},"50":{"tf":1.0},"62":{"tf":1.0},"64":{"tf":1.0},"71":{"tf":1.0},"78":{"tf":1.0},"88":{"tf":1.0}}}},"df":0,"docs":{}}},"m":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":4,"docs":{"0":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"37":{"tf":1.0}}}}}}},"n":{"df":0,"docs":{},"n":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"c":{"df":1,"docs":{"22":{"tf":1.0}}},"df":0,"docs":{}}}}},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":2,"docs":{"71":{"tf":1.0},"75":{"tf":1.0}}}}},"y":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"59":{"tf":1.0}}}}}},"p":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":1,"docs":{"43":{"tf":1.0}}}}},"df":0,"docs":{},"i":{"df":2,"docs":{"70":{"tf":1.0},"76":{"tf":1.4142135623730951}}},"p":{"df":1,"docs":{"91":{"tf":1.0}},"e":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"18":{"tf":1.0}}},"df":0,"docs":{}}},"l":{"df":0,"docs":{},"i":{"c":{"df":2,"docs":{"5":{"tf":1.0},"52":{"tf":1.4142135623730951}}},"df":7,"docs":{"12":{"tf":1.4142135623730951},"27":{"tf":1.0},"37":{"tf":1.0},"40":{"tf":1.0},"52":{"tf":1.0},"68":{"tf":1.0},"87":{"tf":1.0}}}},"r":{"df":0,"docs":{},"o":{"a":{"c":{"df":0,"docs":{},"h":{"df":2,"docs":{"66":{"tf":1.0},"80":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"77":{"tf":1.0}}}}}}}}},"r":{"b":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"30":{"tf":1.0}}}}},"df":0,"docs":{}}}}},"c":{"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":8,"docs":{"43":{"tf":1.0},"66":{"tf":1.7320508075688772},"67":{"tf":1.0},"68":{"tf":1.0},"69":{"tf":1.0},"70":{"tf":1.0},"71":{"tf":1.0},"72":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"u":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":4,"docs":{"30":{"tf":1.0},"39":{"tf":1.0},"43":{"tf":1.7320508075688772},"56":{"tf":1.0}}}}}}}},"m":{"df":1,"docs":{"75":{"tf":1.0}}},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"d":{"df":3,"docs":{"52":{"tf":1.0},"75":{"tf":1.4142135623730951},"89":{"tf":1.0}}},"df":0,"docs":{}}}},"t":{"df":1,"docs":{"75":{"tf":1.0}},"i":{"df":0,"docs":{},"f":{"a":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"16":{"tf":1.7320508075688772}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"s":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":4,"docs":{"58":{"tf":1.0},"61":{"tf":1.0},"64":{"tf":1.0},"65":{"tf":1.0}}}},"df":0,"docs":{}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"b":{"df":0,"docs":{},"l":{"df":5,"docs":{"16":{"tf":1.0},"39":{"tf":1.0},"4":{"tf":1.0},"43":{"tf":1.7320508075688772},"86":{"tf":1.7320508075688772}}}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"t":{"df":2,"docs":{"71":{"tf":1.0},"79":{"tf":1.0}}}},"t":{"df":1,"docs":{"76":{"tf":1.0}}}},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":2,"docs":{"64":{"tf":1.0},"65":{"tf":1.4142135623730951}}}}},"u":{"df":0,"docs":{},"m":{"df":2,"docs":{"43":{"tf":1.0},"50":{"tf":1.0}},"p":{"df":0,"docs":{},"t":{"df":1,"docs":{"75":{"tf":1.0}}}}}}},"t":{"df":2,"docs":{"33":{"tf":1.7320508075688772},"69":{"tf":1.0}}}},"u":{"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"c":{"df":1,"docs":{"1":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"28":{"tf":1.0}}}}}}},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"39":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"t":{"df":3,"docs":{"33":{"tf":1.4142135623730951},"56":{"tf":1.7320508075688772},"62":{"tf":1.0}}}},"df":0,"docs":{}}}}},"v":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":5,"docs":{"14":{"tf":1.0},"21":{"tf":1.0},"22":{"tf":1.0},"50":{"tf":1.0},"75":{"tf":1.0}}}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"i":{"d":{"df":3,"docs":{"56":{"tf":1.0},"62":{"tf":1.0},"64":{"tf":1.7320508075688772}}},"df":0,"docs":{}}}},"w":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"36":{"tf":1.0}}}},"df":0,"docs":{}}},"b":{"a":{"c":{"df":0,"docs":{},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"d":{"df":2,"docs":{"12":{"tf":1.0},"66":{"tf":1.0}}},"df":0,"docs":{}}},"w":{"a":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"76":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"n":{"c":{"df":2,"docs":{"66":{"tf":1.0},"79":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"k":{"df":1,"docs":{"75":{"tf":1.0}}}}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"91":{"tf":1.0}}}}}}},"s":{"df":0,"docs":{},"e":{"df":5,"docs":{"17":{"tf":1.0},"50":{"tf":1.0},"51":{"tf":1.0},"52":{"tf":1.0},"75":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"=":{"1":{"0":{"3":{"0":{"6":{"3":{"/":{"1":{"5":{"7":{"2":{"8":{"6":{"4":{"df":1,"docs":{"57":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"i":{"c":{"df":1,"docs":{"12":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":2,"docs":{"51":{"tf":1.0},"56":{"tf":1.0}}}}},"h":{"a":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":2,"docs":{"50":{"tf":1.0},"64":{"tf":1.0}}}}}}},"df":0,"docs":{}},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":2,"docs":{"75":{"tf":1.0},"91":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"w":{"df":3,"docs":{"18":{"tf":1.0},"39":{"tf":1.0},"92":{"tf":1.0}}}}},"n":{"c":{"df":0,"docs":{},"h":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"k":{"df":2,"docs":{"61":{"tf":1.0},"75":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"52":{"tf":1.0}}}}}}},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"64":{"tf":1.0}}}},"t":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"52":{"tf":1.0}}}}},"w":{"df":0,"docs":{},"e":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":5,"docs":{"12":{"tf":1.0},"35":{"tf":1.0},"50":{"tf":1.0},"66":{"tf":1.0},"72":{"tf":1.0}}}}}}},"y":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"d":{"df":2,"docs":{"52":{"tf":1.0},"77":{"tf":1.0}}},"df":0,"docs":{}}}}},"i":{"df":0,"docs":{},"g":{"df":1,"docs":{"70":{"tf":1.0}}},"n":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":7,"docs":{"5":{"tf":1.0},"53":{"tf":1.0},"67":{"tf":1.0},"68":{"tf":1.4142135623730951},"7":{"tf":1.7320508075688772},"71":{"tf":1.0},"81":{"tf":1.0}}}}},"df":1,"docs":{"19":{"tf":1.0}}},"t":{"df":3,"docs":{"39":{"tf":1.0},"62":{"tf":1.0},"72":{"tf":1.4142135623730951}},"w":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":1,"docs":{"79":{"tf":1.7320508075688772}}}}}}},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"65":{"tf":1.0}}}}},"df":0,"docs":{}}},"o":{"b":{"b":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":1,"docs":{"49":{"tf":1.4142135623730951}}}}}}},"df":0,"docs":{}},"df":6,"docs":{"18":{"tf":1.7320508075688772},"35":{"tf":1.4142135623730951},"49":{"tf":1.0},"67":{"tf":1.0},"68":{"tf":1.0},"92":{"tf":1.0}},"h":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"df":1,"docs":{"49":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}}},"c":{"df":0,"docs":{},"k":{"c":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":5,"docs":{"52":{"tf":1.0},"53":{"tf":1.4142135623730951},"75":{"tf":1.0},"76":{"tf":1.0},"80":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":1,"docs":{"43":{"tf":1.7320508075688772}}}},"df":0,"docs":{}}},"o":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"75":{"tf":1.0}}}},"o":{"df":0,"docs":{},"k":{"df":2,"docs":{"0":{"tf":1.0},"3":{"tf":1.4142135623730951}}},"l":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"n":{"df":1,"docs":{"26":{"tf":1.0}}}},"df":0,"docs":{}}}},"t":{"df":0,"docs":{},"h":{"df":2,"docs":{"18":{"tf":1.0},"35":{"tf":1.0}}}},"u":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"70":{"tf":1.0}}},"df":0,"docs":{}}}},"r":{"a":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"h":{"df":1,"docs":{"63":{"tf":1.7320508075688772}}}},"df":0,"docs":{}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"81":{"tf":1.0}}}}}}}},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"68":{"tf":1.0}}}},"df":0,"docs":{}}}}}},"u":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":5,"docs":{"14":{"tf":1.0},"39":{"tf":1.4142135623730951},"40":{"tf":1.4142135623730951},"43":{"tf":1.4142135623730951},"70":{"tf":1.4142135623730951}}}}}},"g":{"df":5,"docs":{"23":{"tf":1.0},"77":{"tf":1.0},"78":{"tf":1.7320508075688772},"79":{"tf":1.0},"80":{"tf":1.0}},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"x":{"df":1,"docs":{"88":{"tf":1.0}}}}}},"i":{"d":{"df":0,"docs":{},"l":{"df":1,"docs":{"10":{"tf":1.4142135623730951}}}},"df":0,"docs":{},"l":{"d":{"df":8,"docs":{"10":{"tf":1.0},"6":{"tf":1.0},"60":{"tf":1.0},"61":{"tf":1.0},"68":{"tf":2.0},"71":{"tf":2.0},"77":{"tf":1.0},"82":{"tf":2.449489742783178}},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"69":{"tf":1.0},"71":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"71":{"tf":1.0}}}},"t":{"df":1,"docs":{"71":{"tf":1.0}},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"71":{"tf":1.0}}}}}}},"n":{"d":{"df":0,"docs":{},"l":{"df":1,"docs":{"68":{"tf":1.0}}}},"df":0,"docs":{}},"s":{"df":0,"docs":{},"i":{"df":1,"docs":{"52":{"tf":1.0}}}}},"y":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"o":{"d":{"df":4,"docs":{"18":{"tf":1.0},"33":{"tf":1.4142135623730951},"38":{"tf":1.0},"75":{"tf":2.23606797749979}}},"df":0,"docs":{}}},"df":2,"docs":{"40":{"tf":1.0},"70":{"tf":1.4142135623730951}}}}}},"c":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"_":{"d":{"a":{"df":0,"docs":{},"t":{"a":{"_":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"y":{"(":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":1,"docs":{"57":{"tf":1.0}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"s":{"df":1,"docs":{"57":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"18":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"d":{"a":{"df":0,"docs":{},"t":{"a":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":1,"docs":{"41":{"tf":1.4142135623730951}}}}}},"df":2,"docs":{"41":{"tf":1.0},"79":{"tf":1.0}},"l":{"df":0,"docs":{},"o":{"a":{"d":{"df":1,"docs":{"41":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":6,"docs":{"0":{"tf":1.0},"18":{"tf":1.0},"35":{"tf":1.0},"37":{"tf":1.0},"56":{"tf":1.0},"79":{"tf":1.4142135623730951}}}},"n":{"df":0,"docs":{},"’":{"df":0,"docs":{},"t":{"df":1,"docs":{"52":{"tf":1.0}}}}},"p":{"df":1,"docs":{"40":{"tf":1.0}},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":2,"docs":{"65":{"tf":1.4142135623730951},"72":{"tf":1.0}}}}}},"r":{"df":0,"docs":{},"e":{"df":2,"docs":{"18":{"tf":1.0},"66":{"tf":1.0}},"f":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"0":{"tf":1.0}}}}}}}},"g":{"df":0,"docs":{},"o":{".":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{"df":1,"docs":{"62":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":1,"docs":{"62":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"e":{"df":5,"docs":{"18":{"tf":2.0},"48":{"tf":1.0},"49":{"tf":1.0},"79":{"tf":1.4142135623730951},"80":{"tf":1.4142135623730951}}}},"u":{"df":0,"docs":{},"s":{"df":1,"docs":{"80":{"tf":1.0}}}},"v":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"40":{"tf":1.0}}}},"df":0,"docs":{}}}},"d":{"df":1,"docs":{"77":{"tf":1.0}}},"df":1,"docs":{"52":{"tf":1.0}},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"79":{"tf":1.0}}}},"df":0,"docs":{}}}}},"h":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":3,"docs":{"35":{"tf":1.0},"68":{"tf":1.0},"75":{"tf":1.4142135623730951}}}},"n":{"c":{"df":2,"docs":{"52":{"tf":1.0},"61":{"tf":1.0}}},"df":0,"docs":{},"g":{"df":6,"docs":{"18":{"tf":1.0},"3":{"tf":1.0},"37":{"tf":1.0},"62":{"tf":1.0},"63":{"tf":1.4142135623730951},"79":{"tf":1.4142135623730951}}}},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":4,"docs":{"11":{"tf":1.0},"58":{"tf":1.0},"77":{"tf":1.0},"86":{"tf":1.0}}}}}},"r":{"df":1,"docs":{"29":{"tf":1.0}}}},"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"k":{"df":2,"docs":{"70":{"tf":1.0},"88":{"tf":1.0}}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"52":{"tf":1.0}}},"df":0,"docs":{}}}},"i":{"df":2,"docs":{"61":{"tf":1.0},"63":{"tf":1.4142135623730951}},"r":{"c":{"df":0,"docs":{},"u":{"df":0,"docs":{},"m":{"df":0,"docs":{},"v":{"df":1,"docs":{"68":{"tf":1.0}}}}}},"df":0,"docs":{}}},"l":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":1,"docs":{"5":{"tf":1.0}}}}},"df":0,"docs":{},"i":{"df":2,"docs":{"11":{"tf":2.23606797749979},"18":{"tf":1.0}},"p":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":1,"docs":{"64":{"tf":1.0}}}}}},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":1,"docs":{"77":{"tf":1.0}}}},"s":{"df":0,"docs":{},"e":{"df":3,"docs":{"11":{"tf":1.0},"75":{"tf":1.0},"78":{"tf":1.0}}}}}},"o":{"d":{"df":0,"docs":{},"e":{"b":{"a":{"df":0,"docs":{},"s":{"df":4,"docs":{"58":{"tf":1.0},"61":{"tf":1.0},"62":{"tf":1.7320508075688772},"65":{"tf":1.7320508075688772}}}},"df":0,"docs":{}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":1,"docs":{"42":{"tf":1.4142135623730951}}}}}},"df":32,"docs":{"0":{"tf":1.0},"12":{"tf":1.4142135623730951},"13":{"tf":1.0},"14":{"tf":1.0},"17":{"tf":1.0},"18":{"tf":1.4142135623730951},"19":{"tf":1.0},"33":{"tf":1.4142135623730951},"35":{"tf":3.3166247903554},"36":{"tf":1.0},"37":{"tf":1.0},"39":{"tf":1.0},"4":{"tf":1.0},"41":{"tf":1.0},"42":{"tf":1.0},"43":{"tf":2.23606797749979},"5":{"tf":1.0},"53":{"tf":1.4142135623730951},"6":{"tf":1.0},"64":{"tf":1.4142135623730951},"65":{"tf":1.0},"66":{"tf":1.0},"67":{"tf":1.4142135623730951},"68":{"tf":1.7320508075688772},"69":{"tf":1.4142135623730951},"70":{"tf":1.0},"75":{"tf":2.0},"77":{"tf":1.0},"78":{"tf":1.0},"79":{"tf":1.4142135623730951},"89":{"tf":1.0},"92":{"tf":1.4142135623730951}},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":2,"docs":{"50":{"tf":1.0},"51":{"tf":1.0}}}}},"s":{"df":1,"docs":{"35":{"tf":1.0}}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"79":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}}},"m":{"b":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":2,"docs":{"5":{"tf":1.0},"79":{"tf":1.4142135623730951}}}}},"df":0,"docs":{},"e":{"df":2,"docs":{"53":{"tf":1.0},"77":{"tf":1.0}}},"m":{"a":{"df":0,"docs":{},"n":{"d":{"df":10,"docs":{"11":{"tf":1.0},"12":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"15":{"tf":1.0},"16":{"tf":1.0},"17":{"tf":1.0},"18":{"tf":1.0},"19":{"tf":1.0},"30":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"64":{"tf":2.0}}}}},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"52":{"tf":1.0}}}}},"p":{"a":{"df":0,"docs":{},"r":{"df":2,"docs":{"34":{"tf":1.0},"40":{"tf":1.0}},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"0":{"tf":1.0}}}}}}},"t":{"df":8,"docs":{"24":{"tf":1.0},"66":{"tf":1.0},"70":{"tf":1.0},"76":{"tf":1.0},"78":{"tf":1.7320508075688772},"79":{"tf":1.0},"82":{"tf":1.0},"91":{"tf":1.0}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":49,"docs":{"0":{"tf":1.0},"12":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"16":{"tf":1.0},"18":{"tf":2.23606797749979},"19":{"tf":1.0},"22":{"tf":1.4142135623730951},"24":{"tf":1.0},"25":{"tf":1.0},"3":{"tf":1.0},"33":{"tf":1.0},"39":{"tf":1.0},"4":{"tf":1.7320508075688772},"40":{"tf":1.0},"48":{"tf":1.0},"49":{"tf":1.0},"5":{"tf":2.0},"50":{"tf":1.7320508075688772},"52":{"tf":1.0},"57":{"tf":1.0},"58":{"tf":1.0},"59":{"tf":1.0},"6":{"tf":1.7320508075688772},"60":{"tf":1.0},"61":{"tf":1.0},"62":{"tf":1.0},"65":{"tf":1.0},"66":{"tf":2.449489742783178},"67":{"tf":2.0},"68":{"tf":1.7320508075688772},"69":{"tf":2.23606797749979},"70":{"tf":1.4142135623730951},"71":{"tf":1.7320508075688772},"72":{"tf":1.0},"73":{"tf":1.0},"75":{"tf":2.23606797749979},"76":{"tf":1.0},"77":{"tf":1.0},"78":{"tf":1.4142135623730951},"79":{"tf":1.0},"8":{"tf":1.0},"80":{"tf":1.0},"81":{"tf":2.0},"82":{"tf":1.0},"83":{"tf":1.4142135623730951},"9":{"tf":1.0},"91":{"tf":1.4142135623730951},"92":{"tf":1.0}}}},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":3,"docs":{"11":{"tf":1.0},"75":{"tf":1.0},"92":{"tf":1.0}}},"x":{"df":2,"docs":{"52":{"tf":1.0},"80":{"tf":1.4142135623730951}}}},"i":{"c":{"df":1,"docs":{"62":{"tf":1.0}}},"df":0,"docs":{}}},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"5":{"tf":1.4142135623730951}}},"s":{"df":1,"docs":{"52":{"tf":1.0}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":2,"docs":{"61":{"tf":1.0},"80":{"tf":1.0}}}}}}}},"t":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"4":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}},"u":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"52":{"tf":1.0}}}}}}},"df":1,"docs":{"75":{"tf":1.0}}}}}},"n":{"c":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"43":{"tf":1.0}}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":1,"docs":{"61":{"tf":1.0}}}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":8,"docs":{"13":{"tf":1.0},"14":{"tf":1.0},"24":{"tf":1.0},"25":{"tf":1.0},"27":{"tf":1.7320508075688772},"29":{"tf":1.0},"33":{"tf":1.0},"74":{"tf":1.7320508075688772}}}}}},"l":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"64":{"tf":1.0}}}},"df":0,"docs":{}}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"q":{"df":0,"docs":{},"u":{"df":1,"docs":{"18":{"tf":1.0}},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"14":{"tf":1.0}}}}}}}}},"i":{"d":{"df":5,"docs":{"62":{"tf":1.0},"64":{"tf":1.0},"68":{"tf":1.0},"76":{"tf":1.0},"90":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"52":{"tf":1.0}}}}},"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":2,"docs":{"65":{"tf":1.0},"75":{"tf":1.0}}}}},"t":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":5,"docs":{"14":{"tf":1.0},"43":{"tf":1.0},"45":{"tf":1.0},"47":{"tf":1.0},"64":{"tf":1.0}}}}},"df":0,"docs":{},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"56":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"u":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":6,"docs":{"35":{"tf":1.4142135623730951},"41":{"tf":1.0},"42":{"tf":1.0},"43":{"tf":1.7320508075688772},"51":{"tf":1.7320508075688772},"56":{"tf":1.0}}}}}},"df":0,"docs":{}}}}},"t":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":3,"docs":{"39":{"tf":1.0},"43":{"tf":1.0},"5":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"3":{"tf":1.0}}}},"x":{"df":0,"docs":{},"t":{"df":2,"docs":{"65":{"tf":1.0},"69":{"tf":2.0}}}}},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":34,"docs":{"0":{"tf":2.0},"12":{"tf":1.0},"13":{"tf":1.7320508075688772},"14":{"tf":2.0},"18":{"tf":2.0},"2":{"tf":1.7320508075688772},"27":{"tf":1.4142135623730951},"32":{"tf":2.449489742783178},"33":{"tf":2.23606797749979},"35":{"tf":1.4142135623730951},"37":{"tf":1.0},"39":{"tf":1.0},"4":{"tf":1.4142135623730951},"40":{"tf":1.7320508075688772},"43":{"tf":2.0},"44":{"tf":1.0},"45":{"tf":1.0},"50":{"tf":1.0},"51":{"tf":1.4142135623730951},"52":{"tf":2.0},"53":{"tf":1.4142135623730951},"55":{"tf":1.0},"56":{"tf":1.7320508075688772},"57":{"tf":1.4142135623730951},"6":{"tf":1.0},"66":{"tf":1.4142135623730951},"68":{"tf":2.23606797749979},"70":{"tf":1.0},"75":{"tf":2.23606797749979},"76":{"tf":1.0},"78":{"tf":1.4142135623730951},"79":{"tf":2.0},"89":{"tf":1.4142135623730951},"91":{"tf":1.4142135623730951}},"s":{".":{"df":0,"docs":{},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"k":{"a":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{".":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":1,"docs":{"2":{"tf":1.0}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"’":{"df":2,"docs":{"13":{"tf":1.0},"14":{"tf":1.0}}}}},"df":0,"docs":{}},"df":0,"docs":{},"i":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":5,"docs":{"13":{"tf":1.0},"14":{"tf":1.0},"59":{"tf":1.0},"63":{"tf":1.7320508075688772},"65":{"tf":2.0}},"o":{"df":0,"docs":{},"r":{"df":10,"docs":{"1":{"tf":1.0},"58":{"tf":1.0},"59":{"tf":1.7320508075688772},"60":{"tf":1.0},"61":{"tf":1.0},"62":{"tf":1.0},"63":{"tf":1.0},"64":{"tf":1.0},"65":{"tf":1.4142135623730951},"77":{"tf":1.0}}}}}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"l":{"df":4,"docs":{"13":{"tf":1.0},"55":{"tf":1.0},"70":{"tf":1.0},"82":{"tf":1.0}}}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":3,"docs":{"52":{"tf":1.0},"53":{"tf":1.0},"55":{"tf":1.0}}}}}}},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":3,"docs":{"65":{"tf":1.0},"77":{"tf":1.4142135623730951},"79":{"tf":1.0}}}},"df":0,"docs":{},"s":{"df":0,"docs":{},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"d":{"df":4,"docs":{"18":{"tf":1.0},"26":{"tf":1.0},"27":{"tf":1.4142135623730951},"29":{"tf":1.0}}},"df":0,"docs":{}}}}}}}},"s":{"df":0,"docs":{},"t":{"df":3,"docs":{"13":{"tf":1.4142135623730951},"14":{"tf":1.7320508075688772},"43":{"tf":1.0}}}},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"64":{"tf":1.0}},"p":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":1,"docs":{"79":{"tf":1.0}}}}},"df":0,"docs":{}}}}}},"p":{"df":0,"docs":{},"l":{"df":1,"docs":{"52":{"tf":1.0}}}},"r":{"df":0,"docs":{},"s":{"df":1,"docs":{"52":{"tf":1.0}}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"58":{"tf":1.0}}}}}},"p":{"df":0,"docs":{},"u":{"df":2,"docs":{"74":{"tf":1.7320508075688772},"75":{"tf":1.4142135623730951}}}},"r":{"a":{"df":0,"docs":{},"f":{"df":0,"docs":{},"t":{"df":1,"docs":{"43":{"tf":1.0}}}},"t":{"df":0,"docs":{},"e":{"df":3,"docs":{"62":{"tf":2.449489742783178},"69":{"tf":1.7320508075688772},"71":{"tf":1.4142135623730951}},"s":{"/":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"g":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"/":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"s":{"/":{"df":0,"docs":{},"f":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"p":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{".":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":1,"docs":{"19":{"tf":1.0}}}}}},"df":0,"docs":{}}}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"t":{"df":4,"docs":{"43":{"tf":2.0},"62":{"tf":1.0},"65":{"tf":1.0},"80":{"tf":1.0}},"e":{"2":{"df":1,"docs":{"43":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"80":{"tf":1.0}}}}}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":5,"docs":{"61":{"tf":1.0},"71":{"tf":1.4142135623730951},"81":{"tf":2.0},"82":{"tf":1.0},"83":{"tf":1.7320508075688772}}}}},"u":{"c":{"df":0,"docs":{},"i":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"68":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":2,"docs":{"33":{"tf":1.0},"89":{"tf":1.0}}}}}}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"df":3,"docs":{"71":{"tf":1.0},"72":{"tf":1.7320508075688772},"92":{"tf":1.0}}}}}}}},"d":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"p":{"df":7,"docs":{"1":{"tf":1.0},"18":{"tf":1.0},"34":{"tf":1.0},"39":{"tf":1.0},"52":{"tf":1.4142135623730951},"88":{"tf":1.4142135623730951},"91":{"tf":1.4142135623730951}}}},"t":{"a":{"_":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"57":{"tf":1.4142135623730951}}}}},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":1,"docs":{"57":{"tf":1.4142135623730951}}}}}},"df":6,"docs":{"18":{"tf":1.0},"35":{"tf":1.0},"49":{"tf":1.0},"57":{"tf":2.0},"70":{"tf":1.0},"79":{"tf":1.4142135623730951}},"o":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":2,"docs":{"43":{"tf":1.0},"44":{"tf":1.4142135623730951}}}}}}}},"s":{"df":2,"docs":{"43":{"tf":1.0},"45":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}},"df":0,"docs":{},"e":{"a":{"d":{"df":1,"docs":{"52":{"tf":1.0}}},"df":0,"docs":{},"l":{"df":1,"docs":{"39":{"tf":1.0}}}},"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"_":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":0,"docs":{},"p":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"_":{"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"16":{"tf":1.0}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}},"df":6,"docs":{"16":{"tf":2.0},"17":{"tf":2.0},"26":{"tf":1.0},"30":{"tf":1.0},"53":{"tf":1.0},"57":{"tf":1.0}}}}},"c":{"df":0,"docs":{},"i":{"d":{"df":2,"docs":{"18":{"tf":1.0},"80":{"tf":1.0}}},"df":0,"docs":{},"s":{"df":3,"docs":{"64":{"tf":1.0},"75":{"tf":1.0},"91":{"tf":1.0}}}},"l":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"79":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":1,"docs":{"69":{"tf":1.0}}}}}}},"d":{"df":0,"docs":{},"i":{"c":{"df":2,"docs":{"62":{"tf":1.0},"69":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"f":{"a":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":5,"docs":{"12":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"15":{"tf":1.0},"17":{"tf":1.0}}}}}},"df":0,"docs":{},"i":{"df":1,"docs":{"52":{"tf":1.0}},"n":{"df":2,"docs":{"77":{"tf":1.0},"79":{"tf":2.0}}}},"u":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"0":{"tf":1.0}}}},"df":0,"docs":{}}}},"g":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":2,"docs":{"64":{"tf":1.0},"65":{"tf":1.0}}}}},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"g":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"c":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"18":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"t":{"df":1,"docs":{"64":{"tf":1.0}}}},"i":{"df":0,"docs":{},"v":{"df":1,"docs":{"92":{"tf":1.0}}}}},"n":{"df":0,"docs":{},"i":{"df":1,"docs":{"63":{"tf":1.0}}}},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"d":{"df":6,"docs":{"18":{"tf":1.4142135623730951},"62":{"tf":3.0},"68":{"tf":1.0},"71":{"tf":2.0},"8":{"tf":1.4142135623730951},"82":{"tf":1.7320508075688772}}},"df":0,"docs":{}}},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"y":{"df":5,"docs":{"18":{"tf":3.3166247903554},"34":{"tf":1.0},"35":{"tf":2.0},"43":{"tf":2.23606797749979},"89":{"tf":1.4142135623730951}}}}},"r":{"df":0,"docs":{},"e":{"c":{"df":1,"docs":{"52":{"tf":1.0}}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":1,"docs":{"51":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"n":{"df":3,"docs":{"52":{"tf":1.0},"64":{"tf":1.0},"75":{"tf":1.4142135623730951}}}},"r":{"df":2,"docs":{"31":{"tf":1.0},"53":{"tf":1.0}}}},"t":{"df":1,"docs":{"79":{"tf":1.0}}}},"t":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":2,"docs":{"11":{"tf":1.0},"80":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"40":{"tf":1.0}}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"68":{"tf":1.0}}}}}}}}}}},"v":{"df":2,"docs":{"53":{"tf":1.0},"62":{"tf":1.4142135623730951}},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":34,"docs":{"1":{"tf":1.4142135623730951},"16":{"tf":1.0},"17":{"tf":1.0},"20":{"tf":1.0},"30":{"tf":1.0},"34":{"tf":1.0},"52":{"tf":1.0},"58":{"tf":1.7320508075688772},"59":{"tf":1.0},"60":{"tf":1.0},"61":{"tf":1.7320508075688772},"62":{"tf":1.0},"63":{"tf":1.0},"64":{"tf":1.0},"65":{"tf":1.0},"66":{"tf":1.0},"67":{"tf":1.0},"68":{"tf":1.0},"69":{"tf":1.0},"70":{"tf":1.0},"71":{"tf":1.0},"72":{"tf":1.0},"73":{"tf":1.0},"74":{"tf":1.0},"75":{"tf":1.0},"76":{"tf":1.0},"77":{"tf":1.0},"78":{"tf":1.0},"79":{"tf":1.0},"80":{"tf":1.0},"81":{"tf":1.0},"82":{"tf":1.0},"83":{"tf":1.0},"92":{"tf":1.0}}}}}}}},"i":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"34":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":24,"docs":{"0":{"tf":2.23606797749979},"1":{"tf":1.0},"12":{"tf":1.0},"24":{"tf":1.0},"34":{"tf":2.0},"35":{"tf":1.0},"36":{"tf":1.4142135623730951},"37":{"tf":1.0},"38":{"tf":1.0},"39":{"tf":1.4142135623730951},"40":{"tf":1.4142135623730951},"41":{"tf":1.0},"42":{"tf":1.0},"43":{"tf":1.7320508075688772},"44":{"tf":1.0},"45":{"tf":1.0},"46":{"tf":1.0},"47":{"tf":1.0},"48":{"tf":1.0},"49":{"tf":1.0},"50":{"tf":2.23606797749979},"51":{"tf":1.0},"78":{"tf":1.0},"86":{"tf":1.0}},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":4,"docs":{"35":{"tf":1.0},"68":{"tf":1.0},"79":{"tf":3.1622776601683795},"80":{"tf":2.23606797749979}}}}}}}},"i":{"c":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"47":{"tf":1.4142135623730951}}}}}}},"df":0,"docs":{}}}},"r":{"df":2,"docs":{"16":{"tf":1.0},"62":{"tf":1.0}},"e":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"19":{"tf":1.0}}}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":4,"docs":{"16":{"tf":1.0},"18":{"tf":1.4142135623730951},"54":{"tf":1.0},"62":{"tf":1.0}}}}}}},"df":0,"docs":{}}},"s":{"a":{"b":{"df":0,"docs":{},"l":{"df":2,"docs":{"17":{"tf":1.0},"18":{"tf":1.0}}}},"df":0,"docs":{}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"g":{"df":2,"docs":{"18":{"tf":1.4142135623730951},"43":{"tf":1.0}}}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":2,"docs":{"63":{"tf":1.0},"65":{"tf":1.0}}}}}},"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":2,"docs":{"71":{"tf":1.0},"9":{"tf":1.0}}}}},"df":0,"docs":{}}}}}},"o":{"c":{"df":1,"docs":{"64":{"tf":1.0}},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"83":{"tf":1.0}}}}}}}},"u":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":2,"docs":{"3":{"tf":1.0},"8":{"tf":1.0}}}}}}}},"df":1,"docs":{"0":{"tf":1.0}},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"n":{"df":0,"docs":{},"’":{"df":0,"docs":{},"t":{"df":5,"docs":{"19":{"tf":1.0},"37":{"tf":1.0},"62":{"tf":1.0},"64":{"tf":1.0},"70":{"tf":1.0}}}}}}},"m":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"72":{"tf":1.0}}}}},"df":0,"docs":{}},"n":{"df":0,"docs":{},"e":{"df":1,"docs":{"18":{"tf":1.0}}},"’":{"df":0,"docs":{},"t":{"df":5,"docs":{"39":{"tf":1.0},"62":{"tf":1.0},"64":{"tf":1.4142135623730951},"71":{"tf":1.0},"85":{"tf":1.0}}}}},"w":{"df":0,"docs":{},"n":{"df":2,"docs":{"53":{"tf":1.0},"75":{"tf":1.0}}}}},"r":{"df":1,"docs":{"91":{"tf":1.0}},"i":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":3,"docs":{"19":{"tf":1.0},"5":{"tf":1.0},"67":{"tf":1.0}}}}}},"o":{"df":0,"docs":{},"p":{"df":1,"docs":{"90":{"tf":1.7320508075688772}}}}},"u":{"df":0,"docs":{},"e":{"df":7,"docs":{"13":{"tf":1.0},"14":{"tf":1.0},"18":{"tf":1.7320508075688772},"43":{"tf":1.0},"68":{"tf":1.0},"72":{"tf":1.0},"78":{"tf":1.0}}},"m":{"df":0,"docs":{},"p":{"df":1,"docs":{"16":{"tf":1.0}}}},"r":{"df":0,"docs":{},"e":{"df":3,"docs":{"18":{"tf":1.4142135623730951},"71":{"tf":1.0},"8":{"tf":1.0}}}}},"y":{"df":0,"docs":{},"n":{"a":{"df":0,"docs":{},"m":{"df":2,"docs":{"14":{"tf":1.0},"68":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{},"e":{"a":{"c":{"df":0,"docs":{},"h":{"df":2,"docs":{"52":{"tf":1.0},"79":{"tf":1.4142135623730951}}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"80":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"i":{"df":1,"docs":{"5":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":2,"docs":{"52":{"tf":1.0},"64":{"tf":1.0}}}}}}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"s":{"df":0,"docs":{},"y":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":1,"docs":{"91":{"tf":1.0}}}}}}}}}},"d":{"df":0,"docs":{},"g":{"df":1,"docs":{"91":{"tf":1.0}}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":2,"docs":{"75":{"tf":1.0},"79":{"tf":1.0}}}},"df":0,"docs":{}},"i":{"c":{"df":0,"docs":{},"i":{"df":1,"docs":{"75":{"tf":1.0}}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":4,"docs":{"52":{"tf":1.0},"64":{"tf":1.0},"66":{"tf":1.0},"91":{"tf":1.0}}}}}}},"l":{"df":0,"docs":{},"f":{"df":5,"docs":{"16":{"tf":1.0},"18":{"tf":1.4142135623730951},"67":{"tf":1.4142135623730951},"74":{"tf":1.0},"81":{"tf":1.0}}},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":2,"docs":{"80":{"tf":1.0},"91":{"tf":1.0}}}}}}},"m":{"b":{"df":0,"docs":{},"e":{"d":{"df":1,"docs":{"75":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":7,"docs":{"18":{"tf":1.0},"35":{"tf":1.0},"39":{"tf":1.0},"67":{"tf":1.0},"69":{"tf":1.0},"70":{"tf":1.4142135623730951},"92":{"tf":1.4142135623730951}}}},"p":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"y":{"df":1,"docs":{"68":{"tf":1.0}}}}},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"57":{"tf":1.0}}}}},"s":{"c":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":3,"docs":{"7":{"tf":1.0},"71":{"tf":1.0},"82":{"tf":1.7320508075688772}}}}}}}}},"d":{"df":0,"docs":{},"k":{"/":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":0,"docs":{},"s":{"d":{"df":0,"docs":{},"k":{"_":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"v":{".":{"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"df":1,"docs":{"82":{"tf":1.0}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":1,"docs":{"82":{"tf":1.0}}}},"df":0,"docs":{}},"u":{"df":0,"docs":{},"l":{"df":3,"docs":{"14":{"tf":1.0},"40":{"tf":1.0},"70":{"tf":1.0}}}}},"n":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"26":{"tf":1.0}}}},"df":0,"docs":{}},"c":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"s":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":2,"docs":{"61":{"tf":1.0},"69":{"tf":1.0}}}}}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"g":{"df":1,"docs":{"77":{"tf":1.0}}}},"df":0,"docs":{}}}}},"d":{"df":1,"docs":{"52":{"tf":1.4142135623730951}},"i":{"a":{"df":0,"docs":{},"n":{"df":1,"docs":{"70":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":2,"docs":{"52":{"tf":1.0},"66":{"tf":1.0}}}},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"df":1,"docs":{"64":{"tf":1.0}}}}}}},"j":{"df":0,"docs":{},"o":{"df":0,"docs":{},"y":{"df":1,"docs":{"65":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":2,"docs":{"64":{"tf":1.0},"65":{"tf":1.0}}}}}},"s":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":3,"docs":{"63":{"tf":1.0},"68":{"tf":1.0},"79":{"tf":1.4142135623730951}}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"r":{"df":1,"docs":{"75":{"tf":1.0}}}},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"91":{"tf":1.0}}},"y":{"df":0,"docs":{},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"5":{"tf":1.0}}}}}}}}}},"v":{"df":1,"docs":{"82":{"tf":1.0}},"i":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":6,"docs":{"53":{"tf":1.0},"55":{"tf":1.0},"72":{"tf":1.0},"76":{"tf":2.0},"81":{"tf":1.0},"82":{"tf":1.4142135623730951}}}}}}}},"q":{"df":0,"docs":{},"u":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"35":{"tf":1.0}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"l":{"df":2,"docs":{"4":{"tf":1.0},"75":{"tf":1.0}}}},"df":0,"docs":{}}}}},"r":{"df":0,"docs":{},"r":{"(":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{":":{":":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"(":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"d":{"a":{"df":0,"docs":{},"t":{"a":{"df":1,"docs":{"57":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":5,"docs":{"39":{"tf":1.0},"40":{"tf":1.0},"48":{"tf":1.0},"49":{"tf":1.0},"79":{"tf":1.0}}}}}},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"u":{"df":0,"docs":{},"m":{"/":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"d":{"/":{"b":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"/":{":":{"$":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"77":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":13,"docs":{"0":{"tf":1.0},"11":{"tf":1.0},"34":{"tf":1.0},"4":{"tf":1.0},"40":{"tf":1.0},"49":{"tf":1.0},"6":{"tf":1.0},"66":{"tf":1.4142135623730951},"77":{"tf":1.7320508075688772},"78":{"tf":1.7320508075688772},"79":{"tf":2.23606797749979},"8":{"tf":1.0},"91":{"tf":1.0}}}}}}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":4,"docs":{"52":{"tf":1.0},"65":{"tf":1.0},"75":{"tf":1.0},"91":{"tf":1.0}},"t":{"df":0,"docs":{},"u":{"df":2,"docs":{"13":{"tf":1.0},"14":{"tf":1.0}}}}}},"m":{".":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"33":{"tf":1.0}}}},"df":0,"docs":{}}}}}},"b":{"df":0,"docs":{},"y":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"o":{"d":{"df":1,"docs":{"33":{"tf":1.7320508075688772}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"33":{"tf":1.7320508075688772}}}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}}},"df":32,"docs":{"0":{"tf":1.4142135623730951},"1":{"tf":1.0},"14":{"tf":1.4142135623730951},"33":{"tf":1.7320508075688772},"34":{"tf":2.0},"35":{"tf":1.4142135623730951},"36":{"tf":1.0},"37":{"tf":1.0},"38":{"tf":1.0},"39":{"tf":1.0},"4":{"tf":1.0},"40":{"tf":1.7320508075688772},"41":{"tf":1.0},"42":{"tf":1.0},"43":{"tf":1.7320508075688772},"44":{"tf":1.0},"45":{"tf":1.0},"46":{"tf":1.0},"47":{"tf":1.0},"48":{"tf":1.4142135623730951},"49":{"tf":1.0},"50":{"tf":1.0},"51":{"tf":1.4142135623730951},"52":{"tf":1.7320508075688772},"70":{"tf":2.23606797749979},"72":{"tf":1.4142135623730951},"75":{"tf":2.23606797749979},"77":{"tf":1.0},"78":{"tf":1.0},"79":{"tf":2.6457513110645907},"85":{"tf":1.7320508075688772},"89":{"tf":1.0}}}},"x":{"a":{"c":{"df":0,"docs":{},"t":{"df":3,"docs":{"18":{"tf":1.0},"74":{"tf":1.0},"80":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":2,"docs":{"68":{"tf":1.0},"79":{"tf":1.0}}}}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":13,"docs":{"0":{"tf":1.0},"18":{"tf":1.0},"5":{"tf":1.0},"51":{"tf":1.4142135623730951},"52":{"tf":1.4142135623730951},"57":{"tf":1.4142135623730951},"61":{"tf":1.0},"63":{"tf":1.0},"68":{"tf":1.0},"79":{"tf":1.4142135623730951},"80":{"tf":1.0},"82":{"tf":1.0},"83":{"tf":1.0}}}}}},"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":1,"docs":{"52":{"tf":1.0}}},"p":{"df":0,"docs":{},"t":{"df":1,"docs":{"63":{"tf":1.0}}}}}},"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":15,"docs":{"12":{"tf":1.7320508075688772},"13":{"tf":1.0},"14":{"tf":1.0},"15":{"tf":1.0},"39":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.4142135623730951},"55":{"tf":1.4142135623730951},"57":{"tf":1.0},"75":{"tf":1.4142135623730951},"79":{"tf":2.449489742783178},"80":{"tf":1.0},"81":{"tf":1.0},"82":{"tf":1.0},"83":{"tf":1.0}}}}},"df":0,"docs":{}},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":2,"docs":{"11":{"tf":1.0},"89":{"tf":1.0}}}}},"p":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":4,"docs":{"43":{"tf":1.4142135623730951},"52":{"tf":1.0},"64":{"tf":1.0},"79":{"tf":1.4142135623730951}}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":2,"docs":{"52":{"tf":1.0},"75":{"tf":1.7320508075688772}}}},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"52":{"tf":1.0}}}}},"l":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":4,"docs":{"11":{"tf":1.0},"18":{"tf":1.0},"64":{"tf":1.0},"77":{"tf":1.0}}}}},"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"18":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"33":{"tf":1.0}}}}}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}}},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"14":{"tf":1.0}}}}}}},"r":{"df":0,"docs":{},"t":{"df":2,"docs":{"77":{"tf":1.0},"82":{"tf":1.4142135623730951}}}},"s":{"df":3,"docs":{"12":{"tf":1.0},"19":{"tf":1.0},"76":{"tf":1.0}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"64":{"tf":1.7320508075688772}}}}}}},"t":{"c":{"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":1,"docs":{"48":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":1,"docs":{"18":{"tf":1.4142135623730951}}}}}}}},"f":{"a":{"c":{"df":0,"docs":{},"e":{"df":1,"docs":{"5":{"tf":1.0}}},"t":{"df":3,"docs":{"18":{"tf":1.0},"65":{"tf":1.0},"75":{"tf":1.0}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"18":{"tf":1.4142135623730951}}}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":3,"docs":{"18":{"tf":1.4142135623730951},"65":{"tf":1.0},"89":{"tf":1.4142135623730951}}}},"l":{"df":0,"docs":{},"l":{"df":2,"docs":{"43":{"tf":1.0},"75":{"tf":1.0}}}},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"43":{"tf":1.0}}}}}},"q":{"df":7,"docs":{"84":{"tf":1.7320508075688772},"85":{"tf":1.0},"86":{"tf":1.0},"87":{"tf":1.0},"88":{"tf":1.0},"89":{"tf":1.0},"90":{"tf":1.0}}},"r":{"df":2,"docs":{"52":{"tf":1.0},"75":{"tf":1.0}}},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"52":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"4":{"tf":1.0},"75":{"tf":1.0}}}}}}},"df":1,"docs":{"57":{"tf":1.0}},"e":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"66":{"tf":1.0}}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":6,"docs":{"18":{"tf":1.0},"4":{"tf":1.0},"77":{"tf":1.0},"86":{"tf":1.0},"88":{"tf":1.0},"92":{"tf":1.0}}}}}},"df":0,"docs":{},"w":{"df":4,"docs":{"11":{"tf":1.0},"24":{"tf":1.0},"40":{"tf":1.0},"64":{"tf":1.0}}}},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"d":{"df":2,"docs":{"32":{"tf":2.0},"33":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"l":{"df":0,"docs":{},"e":{"df":7,"docs":{"16":{"tf":1.0},"17":{"tf":1.0},"32":{"tf":2.8284271247461903},"33":{"tf":1.4142135623730951},"57":{"tf":1.0},"62":{"tf":1.4142135623730951},"67":{"tf":1.0}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"55":{"tf":1.0}}}}}},"n":{"a":{"df":0,"docs":{},"l":{"df":3,"docs":{"67":{"tf":1.0},"79":{"tf":1.0},"82":{"tf":1.4142135623730951}}}},"d":{"df":3,"docs":{"1":{"tf":1.0},"7":{"tf":1.0},"88":{"tf":1.0}}},"df":0,"docs":{},"e":{"df":6,"docs":{"0":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"55":{"tf":1.0},"61":{"tf":1.0},"68":{"tf":1.0}}},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"df":1,"docs":{"57":{"tf":1.4142135623730951}}}},"t":{"df":1,"docs":{"14":{"tf":1.0}}}}},"r":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":2,"docs":{"32":{"tf":1.0},"92":{"tf":1.0}}}}},"x":{"df":5,"docs":{"0":{"tf":1.4142135623730951},"40":{"tf":1.4142135623730951},"63":{"tf":1.0},"65":{"tf":1.0},"77":{"tf":1.0}}}},"l":{"a":{"df":0,"docs":{},"g":{"df":3,"docs":{"18":{"tf":1.0},"57":{"tf":2.0},"70":{"tf":1.0}}},"w":{"df":1,"docs":{"75":{"tf":1.4142135623730951}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"p":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{".":{"df":0,"docs":{},"p":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{"df":1,"docs":{"57":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}}}}}}},"o":{"c":{"df":0,"docs":{},"u":{"df":1,"docs":{"92":{"tf":1.0}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":13,"docs":{"10":{"tf":1.0},"12":{"tf":1.0},"36":{"tf":1.0},"52":{"tf":1.0},"6":{"tf":1.0},"64":{"tf":1.0},"65":{"tf":1.0},"67":{"tf":1.4142135623730951},"68":{"tf":1.0},"7":{"tf":1.0},"78":{"tf":1.0},"79":{"tf":1.0},"80":{"tf":1.0}}}}}},"r":{"c":{"df":1,"docs":{"63":{"tf":1.0}}},"df":0,"docs":{},"k":{"df":2,"docs":{"21":{"tf":1.7320508075688772},"23":{"tf":1.0}}},"m":{"a":{"df":0,"docs":{},"t":{"df":3,"docs":{"18":{"tf":1.0},"79":{"tf":1.0},"80":{"tf":1.0}},"t":{"df":1,"docs":{"64":{"tf":1.0}}}}},"df":0,"docs":{}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"e":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"65":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"u":{"df":0,"docs":{},"m":{"df":1,"docs":{"22":{"tf":1.0}}}}},"u":{"df":0,"docs":{},"n":{"d":{"df":5,"docs":{"18":{"tf":1.0},"3":{"tf":1.0},"62":{"tf":1.0},"74":{"tf":1.0},"75":{"tf":1.0}},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"21":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}}}},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"75":{"tf":1.0}}}}}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":1,"docs":{"57":{"tf":1.4142135623730951}},"w":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"k":{"df":1,"docs":{"66":{"tf":1.0}}}}}}}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"d":{"df":5,"docs":{"5":{"tf":1.0},"6":{"tf":1.0},"66":{"tf":1.0},"81":{"tf":1.0},"82":{"tf":1.0}}},"df":0,"docs":{}}}}}}},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":1,"docs":{"33":{"tf":1.0}},"i":{"df":4,"docs":{"63":{"tf":1.0},"64":{"tf":1.0},"68":{"tf":1.4142135623730951},"74":{"tf":1.0}}}}},"n":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":6,"docs":{"39":{"tf":2.0},"40":{"tf":1.4142135623730951},"51":{"tf":1.4142135623730951},"64":{"tf":1.4142135623730951},"71":{"tf":1.0},"92":{"tf":1.0}}}}}}},"d":{"df":1,"docs":{"65":{"tf":1.0}}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":3,"docs":{"79":{"tf":1.0},"80":{"tf":1.0},"89":{"tf":1.0}},"m":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":2,"docs":{"71":{"tf":1.0},"72":{"tf":1.0}}}}}}}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"43":{"tf":1.0}}}},"u":{"df":0,"docs":{},"r":{"df":3,"docs":{"18":{"tf":1.0},"65":{"tf":1.0},"89":{"tf":1.0}}}}}}},"g":{"a":{"df":8,"docs":{"0":{"tf":1.7320508075688772},"13":{"tf":1.0},"14":{"tf":1.4142135623730951},"37":{"tf":2.0},"40":{"tf":1.0},"43":{"tf":1.4142135623730951},"70":{"tf":1.0},"72":{"tf":1.0}},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"75":{"tf":1.0}}}},"s":{"_":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":0,"docs":{},"u":{"df":0,"docs":{},"m":{"df":1,"docs":{"57":{"tf":2.449489742783178}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"v":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"91":{"tf":1.0}}}}}},"df":2,"docs":{"17":{"tf":1.0},"26":{"tf":1.0}},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":16,"docs":{"17":{"tf":1.0},"2":{"tf":1.0},"33":{"tf":2.0},"40":{"tf":1.0},"5":{"tf":1.0},"52":{"tf":1.0},"6":{"tf":1.0},"61":{"tf":1.0},"64":{"tf":1.0},"65":{"tf":2.0},"66":{"tf":1.0},"68":{"tf":1.0},"69":{"tf":1.4142135623730951},"75":{"tf":1.0},"77":{"tf":1.0},"88":{"tf":1.0}}}}},"t":{"df":4,"docs":{"1":{"tf":1.0},"52":{"tf":1.0},"58":{"tf":1.0},"60":{"tf":1.4142135623730951}}}},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"77":{"tf":1.0}},"h":{"df":0,"docs":{},"u":{"b":{"df":1,"docs":{"63":{"tf":1.0}}},"df":0,"docs":{}}}},"v":{"df":0,"docs":{},"e":{"df":1,"docs":{"92":{"tf":1.0}},"n":{"df":3,"docs":{"65":{"tf":1.0},"68":{"tf":1.0},"92":{"tf":1.0}}}}}},"l":{"a":{"d":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"59":{"tf":1.0}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"o":{"d":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{".":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":1,"docs":{"22":{"tf":1.0}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":2,"docs":{"77":{"tf":1.4142135623730951},"79":{"tf":1.4142135623730951}},"e":{"df":1,"docs":{"77":{"tf":1.0}}},"o":{"d":{"df":2,"docs":{"61":{"tf":1.0},"66":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"r":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"55":{"tf":1.0}}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"52":{"tf":1.0}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"61":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"w":{"df":1,"docs":{"14":{"tf":1.0}}}}},"u":{"a":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":1,"docs":{"75":{"tf":1.0}}}}}},"df":0,"docs":{}}},"df":0,"docs":{},"i":{"d":{"df":76,"docs":{"1":{"tf":1.4142135623730951},"10":{"tf":1.0},"11":{"tf":1.0},"12":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"15":{"tf":1.0},"16":{"tf":1.0},"17":{"tf":1.0},"18":{"tf":1.0},"19":{"tf":1.0},"20":{"tf":1.0},"21":{"tf":1.0},"22":{"tf":1.0},"23":{"tf":1.0},"24":{"tf":1.0},"25":{"tf":1.0},"26":{"tf":1.0},"27":{"tf":1.0},"28":{"tf":1.0},"29":{"tf":1.0},"30":{"tf":1.0},"31":{"tf":1.0},"32":{"tf":1.0},"33":{"tf":1.0},"34":{"tf":1.0},"35":{"tf":1.0},"36":{"tf":1.0},"37":{"tf":1.0},"38":{"tf":1.0},"39":{"tf":1.0},"4":{"tf":1.7320508075688772},"40":{"tf":1.0},"41":{"tf":1.0},"42":{"tf":1.0},"43":{"tf":1.0},"44":{"tf":1.0},"45":{"tf":1.0},"46":{"tf":1.0},"47":{"tf":1.0},"48":{"tf":1.0},"49":{"tf":1.0},"5":{"tf":1.0},"50":{"tf":1.0},"51":{"tf":1.0},"52":{"tf":1.0},"58":{"tf":1.7320508075688772},"59":{"tf":2.0},"6":{"tf":1.0},"60":{"tf":1.4142135623730951},"61":{"tf":1.4142135623730951},"62":{"tf":1.4142135623730951},"63":{"tf":1.4142135623730951},"64":{"tf":2.0},"65":{"tf":1.4142135623730951},"66":{"tf":1.0},"67":{"tf":1.0},"68":{"tf":1.0},"69":{"tf":1.0},"7":{"tf":1.0},"70":{"tf":1.0},"71":{"tf":1.0},"72":{"tf":1.0},"73":{"tf":1.0},"74":{"tf":1.0},"75":{"tf":1.0},"76":{"tf":1.0},"77":{"tf":1.0},"78":{"tf":1.4142135623730951},"79":{"tf":1.0},"8":{"tf":1.0},"80":{"tf":1.0},"81":{"tf":1.0},"82":{"tf":1.0},"83":{"tf":1.0},"9":{"tf":1.0}}},"df":0,"docs":{}}}},"h":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"f":{"df":1,"docs":{"75":{"tf":1.0}}},"l":{"df":0,"docs":{},"u":{"c":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"65":{"tf":1.0}}}}},"df":0,"docs":{}}}},"n":{"d":{"df":1,"docs":{"75":{"tf":1.0}},"i":{"df":1,"docs":{"53":{"tf":1.0}}}},"df":0,"docs":{}},"p":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":2,"docs":{"18":{"tf":1.4142135623730951},"67":{"tf":1.0}}}}}},"r":{"d":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"21":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"w":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"75":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"s":{"df":0,"docs":{},"h":{"df":7,"docs":{"0":{"tf":1.0},"18":{"tf":1.0},"38":{"tf":1.0},"43":{"tf":2.0},"44":{"tf":1.0},"45":{"tf":1.0},"68":{"tf":1.0}},"m":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"68":{"tf":1.0}}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"e":{"a":{"d":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{},"p":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"z":{"df":1,"docs":{"14":{"tf":1.0}}}}}},"df":5,"docs":{"0":{"tf":1.0},"14":{"tf":2.6457513110645907},"27":{"tf":1.4142135623730951},"40":{"tf":1.0},"70":{"tf":2.23606797749979}}},"v":{"df":0,"docs":{},"i":{"df":1,"docs":{"66":{"tf":1.0}}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":1,"docs":{"0":{"tf":1.0}}}},"p":{"df":4,"docs":{"1":{"tf":1.0},"11":{"tf":1.7320508075688772},"54":{"tf":1.4142135623730951},"58":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"79":{"tf":1.0}}}}}},"n":{"c":{"df":1,"docs":{"70":{"tf":1.0}}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"e":{"df":4,"docs":{"51":{"tf":1.0},"65":{"tf":1.0},"74":{"tf":1.0},"88":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":4,"docs":{"4":{"tf":1.0},"66":{"tf":1.0},"79":{"tf":1.0},"91":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":3,"docs":{"34":{"tf":1.0},"64":{"tf":1.0},"78":{"tf":1.0}}}}}}}}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"69":{"tf":1.0}}}}}}},"o":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":1,"docs":{"65":{"tf":1.0}}}},"o":{"d":{"df":1,"docs":{"67":{"tf":1.0}}},"df":0,"docs":{}},"s":{"df":0,"docs":{},"t":{"df":2,"docs":{"76":{"tf":1.7320508075688772},"82":{"tf":1.0}}}}},"t":{"df":0,"docs":{},"t":{"df":0,"docs":{},"p":{"df":0,"docs":{},"s":{":":{"/":{"/":{"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"u":{"b":{".":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"/":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"u":{"df":0,"docs":{},"m":{"/":{"df":0,"docs":{},"g":{"df":0,"docs":{},"o":{"df":1,"docs":{"77":{"tf":1.0}}}}},"df":0,"docs":{}}}}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"u":{"b":{"df":1,"docs":{"76":{"tf":1.0}}},"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"n":{"df":1,"docs":{"65":{"tf":1.0}}}},"df":0,"docs":{}}}},"i":{".":{"df":1,"docs":{"18":{"tf":1.4142135623730951}}},"d":{"df":2,"docs":{"23":{"tf":1.7320508075688772},"33":{"tf":1.0}},"e":{"a":{"df":1,"docs":{"52":{"tf":1.0}},"l":{"df":1,"docs":{"75":{"tf":1.0}}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":2,"docs":{"68":{"tf":1.0},"80":{"tf":1.0}}}}}}}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"n":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":3,"docs":{"0":{"tf":1.0},"41":{"tf":1.0},"75":{"tf":1.4142135623730951}}}}}},"m":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":12,"docs":{"0":{"tf":1.4142135623730951},"4":{"tf":1.0},"52":{"tf":2.449489742783178},"6":{"tf":1.0},"62":{"tf":1.0},"69":{"tf":2.23606797749979},"72":{"tf":1.0},"75":{"tf":1.0},"77":{"tf":1.7320508075688772},"78":{"tf":1.0},"79":{"tf":1.7320508075688772},"80":{"tf":1.4142135623730951}}}}}}},"i":{"df":2,"docs":{"18":{"tf":1.0},"40":{"tf":1.0}}}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":3,"docs":{"1":{"tf":1.0},"64":{"tf":1.0},"65":{"tf":1.0}}}}},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"v":{"df":2,"docs":{"88":{"tf":1.0},"92":{"tf":1.0}}}}}}},"n":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":2,"docs":{"13":{"tf":1.0},"14":{"tf":1.0}}}}}}},"l":{"df":0,"docs":{},"u":{"d":{"df":8,"docs":{"13":{"tf":1.0},"14":{"tf":1.0},"16":{"tf":1.0},"33":{"tf":1.0},"4":{"tf":1.0},"52":{"tf":1.0},"55":{"tf":1.0},"62":{"tf":1.0}}},"df":0,"docs":{}}},"o":{"df":0,"docs":{},"m":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"18":{"tf":1.0}}}}}}}},"r":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"s":{"df":3,"docs":{"13":{"tf":1.7320508075688772},"14":{"tf":1.0},"89":{"tf":1.0}}}},"df":0,"docs":{}}}},"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"76":{"tf":1.0}}}}}}}},"u":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":2,"docs":{"52":{"tf":1.0},"75":{"tf":1.0}}}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"i":{"df":2,"docs":{"52":{"tf":1.0},"75":{"tf":1.0}}}},"df":0,"docs":{}}}}},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"14":{"tf":1.0}}}}}},"o":{"df":1,"docs":{"17":{"tf":1.4142135623730951}},"r":{"df":0,"docs":{},"m":{"df":3,"docs":{"17":{"tf":1.0},"2":{"tf":1.0},"26":{"tf":1.0}}}}},"r":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"u":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"5":{"tf":1.0}}}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"52":{"tf":1.0},"65":{"tf":1.0}},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"51":{"tf":1.4142135623730951}}}}}}},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":3,"docs":{"30":{"tf":1.0},"51":{"tf":1.7320508075688772},"76":{"tf":1.0}}}}},"k":{"df":0,"docs":{},"w":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":1,"docs":{"71":{"tf":1.0}}}}}},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":4,"docs":{"18":{"tf":2.23606797749979},"4":{"tf":1.0},"64":{"tf":1.0},"86":{"tf":1.7320508075688772}}}}},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"u":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"d":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"d":{"df":1,"docs":{"51":{"tf":1.7320508075688772}}},"df":0,"docs":{}}}}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}},"t":{"df":0,"docs":{},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"51":{"tf":1.7320508075688772}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}},"p":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"18":{"tf":1.0}}}}}},"df":3,"docs":{"18":{"tf":1.4142135623730951},"22":{"tf":1.0},"24":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"i":{"d":{"df":5,"docs":{"18":{"tf":1.0},"43":{"tf":1.0},"54":{"tf":1.0},"70":{"tf":1.0},"80":{"tf":1.0}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":1,"docs":{"55":{"tf":1.0}}}}}},"t":{"a":{"df":0,"docs":{},"l":{"df":9,"docs":{"10":{"tf":1.0},"54":{"tf":2.449489742783178},"6":{"tf":2.0},"61":{"tf":1.0},"7":{"tf":1.4142135623730951},"77":{"tf":1.0},"8":{"tf":2.0},"82":{"tf":1.4142135623730951},"9":{"tf":1.0}}},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":4,"docs":{"0":{"tf":1.0},"43":{"tf":1.0},"56":{"tf":1.7320508075688772},"79":{"tf":1.7320508075688772}}}}}},"df":0,"docs":{},"e":{"a":{"d":{"df":10,"docs":{"0":{"tf":1.4142135623730951},"14":{"tf":1.0},"18":{"tf":1.0},"35":{"tf":1.4142135623730951},"38":{"tf":1.0},"43":{"tf":1.4142135623730951},"53":{"tf":1.0},"64":{"tf":1.0},"68":{"tf":1.0},"79":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"u":{"c":{"df":0,"docs":{},"t":{"df":7,"docs":{"10":{"tf":1.0},"18":{"tf":1.0},"35":{"tf":1.0},"43":{"tf":1.0},"55":{"tf":1.0},"75":{"tf":1.0},"8":{"tf":1.0}}}},"df":0,"docs":{}}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"g":{"df":0,"docs":{},"r":{"df":7,"docs":{"20":{"tf":2.0},"21":{"tf":1.0},"22":{"tf":1.0},"23":{"tf":1.0},"52":{"tf":1.0},"77":{"tf":1.7320508075688772},"79":{"tf":2.23606797749979}}}},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"76":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"f":{"a":{"c":{"df":22,"docs":{"11":{"tf":1.0},"12":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"15":{"tf":1.0},"16":{"tf":1.0},"17":{"tf":1.0},"18":{"tf":1.0},"24":{"tf":2.0},"25":{"tf":1.0},"26":{"tf":1.0},"27":{"tf":1.0},"28":{"tf":1.0},"29":{"tf":1.0},"30":{"tf":1.0},"31":{"tf":1.0},"32":{"tf":1.0},"33":{"tf":1.0},"52":{"tf":1.0},"69":{"tf":1.0},"71":{"tf":1.7320508075688772},"76":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"m":{"df":0,"docs":{},"e":{"d":{"df":0,"docs":{},"i":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"16":{"tf":1.0}}}}},"df":2,"docs":{"66":{"tf":1.0},"67":{"tf":1.0}}}},"df":0,"docs":{}}},"n":{"df":4,"docs":{"51":{"tf":1.4142135623730951},"58":{"tf":1.0},"66":{"tf":1.4142135623730951},"68":{"tf":1.0}}},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"75":{"tf":1.4142135623730951}}}}}}}},"r":{"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"u":{"c":{"df":3,"docs":{"0":{"tf":1.4142135623730951},"1":{"tf":1.0},"52":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"u":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"64":{"tf":1.0}}}}}},"v":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"d":{"df":1,"docs":{"68":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"v":{"df":2,"docs":{"18":{"tf":1.0},"65":{"tf":1.4142135623730951}}}}}}},"r":{"df":7,"docs":{"16":{"tf":1.4142135623730951},"50":{"tf":2.0},"51":{"tf":1.0},"66":{"tf":1.4142135623730951},"67":{"tf":1.4142135623730951},"69":{"tf":1.0},"72":{"tf":1.0}},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"33":{"tf":1.0}}}}}}}},"s":{"a":{"df":1,"docs":{"75":{"tf":1.0}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"’":{"df":0,"docs":{},"t":{"df":4,"docs":{"0":{"tf":1.0},"18":{"tf":1.0},"75":{"tf":1.0},"78":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"u":{"df":1,"docs":{"63":{"tf":1.0}}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":1,"docs":{"64":{"tf":1.0}}},"r":{"df":1,"docs":{"68":{"tf":1.0}}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"f":{"df":4,"docs":{"5":{"tf":1.0},"52":{"tf":1.0},"63":{"tf":1.0},"71":{"tf":1.0}}}}}},"’":{"d":{"df":1,"docs":{"51":{"tf":1.0}}},"df":6,"docs":{"18":{"tf":1.0},"19":{"tf":1.0},"52":{"tf":1.0},"53":{"tf":1.0},"55":{"tf":1.0},"90":{"tf":1.0}}}}},"j":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":2,"docs":{"4":{"tf":1.0},"75":{"tf":2.23606797749979}}}},"s":{"df":1,"docs":{"19":{"tf":1.7320508075688772}},"o":{"df":0,"docs":{},"n":{"df":11,"docs":{"18":{"tf":1.4142135623730951},"24":{"tf":2.0},"25":{"tf":1.0},"26":{"tf":1.0},"27":{"tf":1.0},"28":{"tf":1.0},"29":{"tf":1.0},"30":{"tf":1.0},"31":{"tf":1.0},"32":{"tf":1.0},"33":{"tf":1.7320508075688772}}}}},"u":{"d":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"65":{"tf":1.0}}}}}}}}},"df":0,"docs":{}}},"k":{"b":{"df":1,"docs":{"57":{"tf":1.0}}},"df":0,"docs":{},"e":{"c":{"c":{"a":{"df":0,"docs":{},"k":{"2":{"5":{"6":{"df":1,"docs":{"38":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{},"e":{"df":0,"docs":{},"p":{"df":5,"docs":{"11":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"65":{"tf":1.0},"91":{"tf":1.0}}}},"p":{"df":0,"docs":{},"t":{"df":2,"docs":{"61":{"tf":1.0},"70":{"tf":1.0}}}},"y":{"df":2,"docs":{"32":{"tf":1.7320508075688772},"79":{"tf":1.0}},"w":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"43":{"tf":1.0}}},"df":0,"docs":{}}}}}},"n":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":3,"docs":{"11":{"tf":1.0},"18":{"tf":1.0},"52":{"tf":1.0}},"l":{"df":0,"docs":{},"e":{"d":{"df":0,"docs":{},"g":{"df":1,"docs":{"72":{"tf":1.0}}}},"df":0,"docs":{}}},"n":{"df":1,"docs":{"18":{"tf":1.0}}}}}}},"l":{"a":{"c":{"df":0,"docs":{},"k":{"df":2,"docs":{"14":{"tf":1.0},"72":{"tf":1.0}}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"u":{"a":{"df":0,"docs":{},"g":{"df":4,"docs":{"22":{"tf":1.0},"52":{"tf":2.6457513110645907},"64":{"tf":1.0},"91":{"tf":1.0}}}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"g":{"df":2,"docs":{"65":{"tf":1.0},"80":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"40":{"tf":1.0},"89":{"tf":1.4142135623730951}}}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"88":{"tf":1.7320508075688772}}}}}},"u":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"h":{"df":1,"docs":{"76":{"tf":1.0}}}},"df":0,"docs":{}}},"y":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"72":{"tf":1.0}}}},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"40":{"tf":1.0}}}}}}},"df":0,"docs":{},"e":{"a":{"d":{"df":4,"docs":{"0":{"tf":1.0},"39":{"tf":1.0},"40":{"tf":1.0},"65":{"tf":1.0}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":1,"docs":{"61":{"tf":1.0}}}},"v":{"df":1,"docs":{"71":{"tf":1.0}}}},"df":1,"docs":{"72":{"tf":1.0}},"g":{"a":{"c":{"df":0,"docs":{},"i":{"df":1,"docs":{"51":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"75":{"tf":1.0}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":10,"docs":{"12":{"tf":2.23606797749979},"32":{"tf":3.1622776601683795},"33":{"tf":1.7320508075688772},"39":{"tf":1.0},"4":{"tf":1.0},"40":{"tf":1.0},"52":{"tf":1.7320508075688772},"55":{"tf":1.0},"66":{"tf":1.0},"79":{"tf":1.0}}}}},"x":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"69":{"tf":1.0}}}}}},"i":{"b":{"c":{"df":1,"docs":{"83":{"tf":1.4142135623730951}}},"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":9,"docs":{"18":{"tf":3.4641016151377544},"5":{"tf":1.0},"52":{"tf":2.449489742783178},"62":{"tf":1.0},"67":{"tf":1.0},"68":{"tf":1.0},"69":{"tf":2.0},"76":{"tf":1.0},"79":{"tf":1.7320508075688772}}}}},"df":0,"docs":{}}},"df":2,"docs":{"65":{"tf":1.0},"91":{"tf":1.0}},"f":{"df":0,"docs":{},"t":{"df":1,"docs":{"66":{"tf":1.0}}}},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":3,"docs":{"37":{"tf":1.0},"40":{"tf":1.0},"89":{"tf":1.0}}}}},"n":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"r":{"df":3,"docs":{"40":{"tf":1.0},"70":{"tf":1.0},"75":{"tf":1.0}}}},"df":11,"docs":{"11":{"tf":1.0},"12":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"15":{"tf":1.0},"16":{"tf":1.0},"17":{"tf":1.0},"18":{"tf":1.0},"19":{"tf":1.0},"30":{"tf":1.0},"64":{"tf":1.0}}},"k":{"a":{"df":0,"docs":{},"g":{"df":1,"docs":{"18":{"tf":1.0}}}},"df":5,"docs":{"18":{"tf":3.7416573867739413},"52":{"tf":1.0},"67":{"tf":1.0},"68":{"tf":1.4142135623730951},"81":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":4,"docs":{"18":{"tf":1.4142135623730951},"67":{"tf":1.0},"71":{"tf":1.0},"74":{"tf":1.0}}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"64":{"tf":1.0}}}}},"u":{"df":0,"docs":{},"x":{"df":2,"docs":{"7":{"tf":1.0},"81":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"39":{"tf":1.0}}}},"t":{"df":0,"docs":{},"t":{"df":0,"docs":{},"l":{"df":1,"docs":{"62":{"tf":1.0}}}}},"v":{"df":0,"docs":{},"e":{"df":3,"docs":{"35":{"tf":1.0},"62":{"tf":1.0},"75":{"tf":1.0}}}}},"l":{"d":{"df":3,"docs":{"67":{"tf":1.0},"71":{"tf":1.4142135623730951},"82":{"tf":1.0}}},"df":1,"docs":{"69":{"tf":1.0}},"m":{"df":1,"docs":{"65":{"tf":1.0}}},"v":{"df":0,"docs":{},"m":{"/":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":0,"docs":{},"s":{"c":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"/":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"82":{"tf":1.0}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}}}},"g":{"df":0,"docs":{},"n":{"df":0,"docs":{},"u":{"/":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"82":{"tf":1.0}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"y":{"df":0,"docs":{},"s":{"_":{"1":{"8":{"1":{"_":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"x":{"=":{"$":{"df":0,"docs":{},"{":{"df":0,"docs":{},"p":{"df":0,"docs":{},"w":{"d":{"df":0,"docs":{},"}":{"/":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"82":{"tf":1.0}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":13,"docs":{"12":{"tf":1.7320508075688772},"16":{"tf":1.0},"29":{"tf":1.0},"30":{"tf":1.0},"5":{"tf":1.0},"52":{"tf":1.0},"66":{"tf":1.4142135623730951},"67":{"tf":1.4142135623730951},"69":{"tf":2.449489742783178},"71":{"tf":2.6457513110645907},"72":{"tf":1.4142135623730951},"82":{"tf":3.0},"92":{"tf":1.0}}}}},"o":{"c":{"a":{"df":0,"docs":{},"l":{"df":4,"docs":{"13":{"tf":1.0},"53":{"tf":1.0},"61":{"tf":1.0},"63":{"tf":1.0}}},"t":{"df":1,"docs":{"62":{"tf":1.0}}}},"df":0,"docs":{},"k":{"df":1,"docs":{"62":{"tf":1.4142135623730951}}}},"df":0,"docs":{},"g":{"df":1,"docs":{"55":{"tf":2.449489742783178}},"i":{"c":{"df":4,"docs":{"52":{"tf":1.0},"69":{"tf":1.4142135623730951},"77":{"tf":1.0},"79":{"tf":1.0}}},"df":0,"docs":{}}},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"23":{"tf":1.0}}}}}},"o":{"df":0,"docs":{},"k":{"df":1,"docs":{"91":{"tf":1.0}}}},"s":{"df":0,"docs":{},"e":{"df":1,"docs":{"75":{"tf":1.0}}},"s":{"df":1,"docs":{"65":{"tf":1.0}}}},"t":{"df":2,"docs":{"79":{"tf":1.0},"80":{"tf":1.0}}},"w":{"df":5,"docs":{"39":{"tf":1.0},"40":{"tf":1.0},"52":{"tf":1.0},"55":{"tf":1.0},"91":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":4,"docs":{"52":{"tf":1.4142135623730951},"66":{"tf":1.0},"67":{"tf":1.4142135623730951},"69":{"tf":1.0}}}}}}},"m":{"a":{"c":{"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":2,"docs":{"13":{"tf":1.0},"72":{"tf":1.4142135623730951}}}}},"o":{"df":1,"docs":{"7":{"tf":1.0}}},"r":{"df":0,"docs":{},"o":{"df":1,"docs":{"64":{"tf":1.4142135623730951}}}}},"d":{"df":0,"docs":{},"e":{"df":1,"docs":{"63":{"tf":1.0}}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"64":{"tf":1.0}}},"df":0,"docs":{}},"n":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"d":{"df":1,"docs":{"75":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}}}},"i":{"df":0,"docs":{},"n":{"df":4,"docs":{"63":{"tf":1.0},"69":{"tf":1.0},"75":{"tf":1.0},"92":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":3,"docs":{"18":{"tf":1.0},"30":{"tf":1.0},"66":{"tf":1.0}}}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"m":{"df":1,"docs":{"52":{"tf":1.0}}}},"df":0,"docs":{}}}}},"t":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":7,"docs":{"23":{"tf":1.0},"60":{"tf":1.0},"63":{"tf":1.0},"65":{"tf":1.7320508075688772},"66":{"tf":1.0},"68":{"tf":1.0},"71":{"tf":1.0}}}}},"df":0,"docs":{}}}},"j":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":2,"docs":{"7":{"tf":1.0},"92":{"tf":1.4142135623730951}}}}},"k":{"df":0,"docs":{},"e":{"df":13,"docs":{"18":{"tf":1.4142135623730951},"19":{"tf":1.0},"3":{"tf":1.0},"43":{"tf":1.0},"52":{"tf":1.0},"54":{"tf":1.0},"61":{"tf":1.0},"63":{"tf":1.0},"64":{"tf":1.0},"68":{"tf":1.0},"70":{"tf":1.0},"77":{"tf":1.0},"82":{"tf":1.7320508075688772}},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"61":{"tf":1.7320508075688772}}}}}}},"n":{"a":{"df":0,"docs":{},"g":{"df":1,"docs":{"77":{"tf":1.0}}}},"df":0,"docs":{},"i":{"df":2,"docs":{"39":{"tf":1.0},"5":{"tf":1.4142135623730951}},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":1,"docs":{"91":{"tf":1.0}}}}}}}},"u":{"a":{"df":0,"docs":{},"l":{"df":2,"docs":{"43":{"tf":1.0},"79":{"tf":1.0}}}},"df":0,"docs":{}}},"p":{"df":1,"docs":{"75":{"tf":1.0}}},"t":{"c":{"df":0,"docs":{},"h":{"df":1,"docs":{"79":{"tf":1.0}}}},"df":0,"docs":{}},"x":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"u":{"df":0,"docs":{},"m":{"df":1,"docs":{"40":{"tf":1.0}}}}}}},"y":{"b":{"df":1,"docs":{"52":{"tf":1.0}}},"df":0,"docs":{}}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":1,"docs":{"40":{"tf":1.4142135623730951}}}}}},"d":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"k":{"df":1,"docs":{"3":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"n":{"df":2,"docs":{"40":{"tf":1.0},"64":{"tf":1.0}},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":1,"docs":{"64":{"tf":1.7320508075688772}}}}}},"s":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"68":{"tf":1.0}}}}}},"c":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"df":1,"docs":{"18":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":7,"docs":{"13":{"tf":1.7320508075688772},"14":{"tf":2.449489742783178},"27":{"tf":1.0},"39":{"tf":1.7320508075688772},"40":{"tf":3.0},"57":{"tf":1.0},"70":{"tf":2.0}}}}}},"r":{"df":0,"docs":{},"g":{"df":1,"docs":{"63":{"tf":1.0}}}},"s":{"df":0,"docs":{},"s":{"a":{"df":0,"docs":{},"g":{"df":2,"docs":{"11":{"tf":1.0},"64":{"tf":1.0}}}},"df":0,"docs":{}}},"t":{"a":{"d":{"a":{"df":0,"docs":{},"t":{"a":{"df":1,"docs":{"33":{"tf":1.7320508075688772}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":3,"docs":{"0":{"tf":1.0},"14":{"tf":1.0},"70":{"tf":1.0}}}}}},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"c":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":1,"docs":{"65":{"tf":1.0}}}}},"df":0,"docs":{}}}},"s":{"df":0,"docs":{},"s":{"df":2,"docs":{"18":{"tf":1.4142135623730951},"72":{"tf":1.4142135623730951}}},"t":{"a":{"df":0,"docs":{},"k":{"df":1,"docs":{"65":{"tf":1.0}}}},"df":0,"docs":{}}},"x":{"df":1,"docs":{"52":{"tf":1.0}}}},"l":{"df":0,"docs":{},"o":{"a":{"d":{"df":1,"docs":{"40":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"df":0,"docs":{}}},"o":{"d":{"df":0,"docs":{},"e":{"df":2,"docs":{"18":{"tf":1.4142135623730951},"50":{"tf":1.4142135623730951}},"l":{"df":5,"docs":{"0":{"tf":1.0},"43":{"tf":1.4142135623730951},"49":{"tf":1.4142135623730951},"52":{"tf":1.0},"65":{"tf":1.0}}}},"u":{"df":0,"docs":{},"l":{"df":2,"docs":{"64":{"tf":1.0},"9":{"tf":1.0}}}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"72":{"tf":1.0}}}}}},"r":{"df":0,"docs":{},"e":{"df":10,"docs":{"11":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"2":{"tf":1.0},"33":{"tf":1.0},"5":{"tf":1.7320508075688772},"53":{"tf":1.0},"55":{"tf":1.0},"75":{"tf":1.4142135623730951},"80":{"tf":1.7320508075688772}}}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":3,"docs":{"24":{"tf":1.0},"75":{"tf":1.0},"92":{"tf":1.0}}}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":1,"docs":{"91":{"tf":1.0}}}}},"v":{"df":0,"docs":{},"e":{"df":1,"docs":{"75":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"z":{"df":0,"docs":{},"e":{"df":1,"docs":{"40":{"tf":1.7320508075688772}}}}},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":1,"docs":{"40":{"tf":1.4142135623730951}}}}}}},"u":{"c":{"df":0,"docs":{},"h":{"df":4,"docs":{"4":{"tf":1.0},"53":{"tf":1.0},"75":{"tf":1.0},"80":{"tf":1.4142135623730951}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":2,"docs":{"5":{"tf":1.0},"52":{"tf":1.0}}}}}}},"s":{"df":0,"docs":{},"l":{"df":4,"docs":{"7":{"tf":1.0},"71":{"tf":1.0},"81":{"tf":1.0},"83":{"tf":2.0}}}}}},"n":{"a":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":4,"docs":{"32":{"tf":1.0},"5":{"tf":1.4142135623730951},"62":{"tf":1.0},"64":{"tf":1.0}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":2,"docs":{"4":{"tf":1.0},"75":{"tf":1.4142135623730951}}}},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"52":{"tf":1.0}}}}}},"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"91":{"tf":1.0}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"e":{"d":{"df":9,"docs":{"18":{"tf":1.7320508075688772},"33":{"tf":1.4142135623730951},"39":{"tf":1.0},"52":{"tf":1.0},"62":{"tf":1.4142135623730951},"64":{"tf":1.0},"71":{"tf":1.0},"75":{"tf":1.0},"91":{"tf":1.0}}},"df":0,"docs":{}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"18":{"tf":1.0},"79":{"tf":1.0}}}}},"w":{"df":3,"docs":{"43":{"tf":1.0},"62":{"tf":1.0},"77":{"tf":1.0}}}},"i":{"c":{"df":0,"docs":{},"e":{"df":1,"docs":{"19":{"tf":1.0}}}},"df":0,"docs":{}},"o":{"d":{"df":0,"docs":{},"e":{".":{"df":0,"docs":{},"j":{"df":3,"docs":{"19":{"tf":1.0},"81":{"tf":1.0},"9":{"tf":1.0}}}},"df":2,"docs":{"53":{"tf":1.4142135623730951},"80":{"tf":1.0}}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"5":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"n":{"df":6,"docs":{"18":{"tf":1.0},"62":{"tf":1.0},"64":{"tf":1.0},"68":{"tf":1.0},"70":{"tf":1.0},"71":{"tf":1.0}}},"t":{"a":{"b":{"df":0,"docs":{},"l":{"df":2,"docs":{"0":{"tf":1.0},"91":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"e":{"df":8,"docs":{"18":{"tf":1.4142135623730951},"19":{"tf":1.0},"33":{"tf":1.0},"39":{"tf":1.0},"52":{"tf":1.0},"74":{"tf":1.0},"75":{"tf":1.0},"79":{"tf":1.0}},"w":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"df":1,"docs":{"39":{"tf":1.0}}}}}}}}}}},"p":{"df":0,"docs":{},"m":{"df":2,"docs":{"19":{"tf":2.23606797749979},"9":{"tf":1.4142135623730951}}},"x":{"df":1,"docs":{"19":{"tf":1.0}}}},"u":{"a":{"df":0,"docs":{},"n":{"c":{"df":2,"docs":{"65":{"tf":1.0},"80":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"75":{"tf":1.0}}}}}}},"m":{"b":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"64":{"tf":1.0},"75":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"27":{"tf":1.4142135623730951}}}}},"t":{"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":2,"docs":{"43":{"tf":1.0},"53":{"tf":1.0}}}}}}}}},"o":{"(":{"df":0,"docs":{},"n":{"df":1,"docs":{"75":{"tf":1.0}}}},"b":{"df":0,"docs":{},"j":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":8,"docs":{"16":{"tf":1.0},"18":{"tf":1.0},"25":{"tf":1.4142135623730951},"27":{"tf":1.4142135623730951},"28":{"tf":1.7320508075688772},"31":{"tf":1.4142135623730951},"67":{"tf":1.4142135623730951},"74":{"tf":1.0}}}},"df":0,"docs":{}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":4,"docs":{"0":{"tf":1.0},"3":{"tf":1.0},"34":{"tf":1.0},"79":{"tf":1.4142135623730951}}}}}},"t":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":2,"docs":{"81":{"tf":1.0},"82":{"tf":1.0}}}}},"df":0,"docs":{}},"v":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":1,"docs":{"64":{"tf":1.0}}}}}}},"df":3,"docs":{"12":{"tf":1.0},"19":{"tf":1.0},"29":{"tf":1.0}},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":3,"docs":{"4":{"tf":1.0},"49":{"tf":1.0},"70":{"tf":1.0}}}},"i":{"c":{"df":0,"docs":{},"i":{"df":3,"docs":{"18":{"tf":1.0},"64":{"tf":1.0},"68":{"tf":1.0}}}},"df":0,"docs":{}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":4,"docs":{"39":{"tf":1.4142135623730951},"40":{"tf":1.0},"41":{"tf":1.0},"57":{"tf":1.0}}}}}}},"k":{"(":{"0":{"df":1,"docs":{"57":{"tf":1.4142135623730951}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":1,"docs":{"57":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}}}}}}}}},"df":0,"docs":{}}}}},"df":1,"docs":{"57":{"tf":1.4142135623730951}}},"n":{"df":5,"docs":{"15":{"tf":1.0},"33":{"tf":1.0},"65":{"tf":1.0},"75":{"tf":1.0},"91":{"tf":1.0}},"w":{"a":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"85":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"p":{"c":{"df":0,"docs":{},"o":{"d":{"df":3,"docs":{"43":{"tf":1.0},"49":{"tf":1.0},"87":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":2,"docs":{"59":{"tf":1.0},"63":{"tf":1.0}}},"r":{"df":3,"docs":{"40":{"tf":1.0},"68":{"tf":1.0},"7":{"tf":1.0}}}},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":1,"docs":{"72":{"tf":1.4142135623730951}}}}}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":12,"docs":{"12":{"tf":3.4641016151377544},"16":{"tf":1.0},"18":{"tf":1.7320508075688772},"28":{"tf":1.0},"29":{"tf":1.0},"4":{"tf":1.0},"40":{"tf":1.0},"52":{"tf":1.0},"67":{"tf":1.0},"70":{"tf":1.0},"72":{"tf":2.449489742783178},"92":{"tf":1.4142135623730951}},"i":{"df":0,"docs":{},"z":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"66":{"tf":1.0}}}}}}},"o":{"df":0,"docs":{},"n":{"df":2,"docs":{"11":{"tf":1.4142135623730951},"19":{"tf":1.4142135623730951}}}}}}},"r":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"51":{"tf":1.4142135623730951},"75":{"tf":1.4142135623730951}}}}},"df":0,"docs":{},"g":{"a":{"df":0,"docs":{},"n":{"df":1,"docs":{"62":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"o":{"df":0,"docs":{},"g":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"72":{"tf":1.0}}}}}}}}},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"w":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":1,"docs":{"18":{"tf":1.0}}}}}}}}},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":2,"docs":{"34":{"tf":1.0},"39":{"tf":1.0}}}}},"t":{"_":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"57":{"tf":1.0}}}}}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"df":1,"docs":{"79":{"tf":1.4142135623730951}}}}},"d":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"23":{"tf":1.0}}}},"df":0,"docs":{}},"df":1,"docs":{"88":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"64":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"f":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"40":{"tf":1.0}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"g":{"a":{"df":1,"docs":{"39":{"tf":1.0}}},"df":0,"docs":{}}}},"p":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":6,"docs":{"16":{"tf":1.0},"17":{"tf":1.0},"31":{"tf":1.0},"32":{"tf":2.23606797749979},"33":{"tf":3.1622776601683795},"55":{"tf":1.0}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":2,"docs":{"32":{"tf":1.4142135623730951},"33":{"tf":1.0}}}},"df":0,"docs":{}}}}}}}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"r":{"c":{"df":0,"docs":{},"h":{"df":2,"docs":{"5":{"tf":1.0},"67":{"tf":1.0}}}},"df":0,"docs":{}}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"df":1,"docs":{"75":{"tf":1.0}}}}},"df":2,"docs":{"68":{"tf":1.0},"91":{"tf":1.0}},"f":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":1,"docs":{"70":{"tf":1.0}}}}}},"h":{"df":0,"docs":{},"e":{"a":{"d":{"df":1,"docs":{"75":{"tf":1.7320508075688772}}},"df":0,"docs":{}},"df":0,"docs":{}}},"r":{"df":0,"docs":{},"i":{"d":{"df":1,"docs":{"51":{"tf":1.0}}},"df":0,"docs":{}}},"v":{"df":0,"docs":{},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"df":1,"docs":{"92":{"tf":1.0}}}}}}}}},"z":{"df":1,"docs":{"12":{"tf":1.0}}}},"p":{"a":{"c":{"df":0,"docs":{},"k":{"a":{"df":0,"docs":{},"g":{"df":3,"docs":{"19":{"tf":2.23606797749979},"77":{"tf":1.0},"9":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"r":{"df":1,"docs":{"80":{"tf":1.0}}}},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":13,"docs":{"0":{"tf":1.7320508075688772},"34":{"tf":1.0},"37":{"tf":1.0},"41":{"tf":1.0},"46":{"tf":1.0},"53":{"tf":1.0},"55":{"tf":1.0},"73":{"tf":2.0},"74":{"tf":1.0},"75":{"tf":1.4142135623730951},"76":{"tf":2.23606797749979},"79":{"tf":1.4142135623730951},"80":{"tf":1.0}}}}}},"n":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"64":{"tf":1.0}}},"df":0,"docs":{}}},"r":{"a":{"c":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"91":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"64":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"21":{"tf":1.4142135623730951}}},"y":{"/":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"c":{"@":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"19":{"tf":1.0}}}}}}},"df":0,"docs":{}}},"df":1,"docs":{"19":{"tf":1.0}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"5":{"tf":1.0},"69":{"tf":1.4142135623730951}}}}},"t":{"df":1,"docs":{"62":{"tf":1.0}},"i":{"df":2,"docs":{"20":{"tf":1.0},"64":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"s":{"df":2,"docs":{"63":{"tf":1.4142135623730951},"75":{"tf":1.0}}}},"t":{"df":0,"docs":{},"h":{"/":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"/":{"df":0,"docs":{},"m":{"df":0,"docs":{},"y":{"/":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{".":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":1,"docs":{"32":{"tf":1.0}}}}}},"1":{".":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":1,"docs":{"33":{"tf":1.0}}}}}},"df":0,"docs":{}},"2":{".":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":1,"docs":{"33":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"=":{"/":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"/":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"/":{"df":0,"docs":{},"g":{"df":0,"docs":{},"o":{"df":1,"docs":{"77":{"tf":1.0}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":3,"docs":{"15":{"tf":1.4142135623730951},"64":{"tf":1.0},"77":{"tf":1.0}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":1,"docs":{"52":{"tf":1.0}}}}}}}},"c":{"df":1,"docs":{"48":{"tf":1.4142135623730951}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"m":{"df":3,"docs":{"12":{"tf":1.0},"66":{"tf":1.0},"88":{"tf":1.0}}}}}}}},"h":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"df":1,"docs":{"78":{"tf":1.0}}}}}}}}}}},"i":{"df":0,"docs":{},"e":{"c":{"df":1,"docs":{"52":{"tf":1.0}}},"df":0,"docs":{}},"n":{"df":1,"docs":{"62":{"tf":1.0}}},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":3,"docs":{"50":{"tf":1.0},"61":{"tf":1.0},"92":{"tf":1.0}}}}}}}},"l":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"m":{"df":4,"docs":{"68":{"tf":1.0},"7":{"tf":1.0},"71":{"tf":1.0},"91":{"tf":1.0}}}}}}}},"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"s":{"df":8,"docs":{"10":{"tf":1.0},"11":{"tf":1.0},"61":{"tf":1.0},"62":{"tf":1.7320508075688772},"64":{"tf":1.4142135623730951},"65":{"tf":1.0},"7":{"tf":1.0},"8":{"tf":1.0}}}},"df":0,"docs":{}}},"o":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"39":{"tf":1.4142135623730951},"43":{"tf":1.4142135623730951}}}}}}},"l":{"a":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{"df":1,"docs":{"4":{"tf":1.0}}}}},"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"i":{"df":1,"docs":{"65":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"k":{"a":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":6,"docs":{"2":{"tf":1.7320508075688772},"4":{"tf":1.0},"49":{"tf":1.0},"52":{"tf":1.0},"73":{"tf":1.0},"76":{"tf":1.0}}}}},"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{"df":7,"docs":{"1":{"tf":1.0},"5":{"tf":1.0},"55":{"tf":1.0},"6":{"tf":1.4142135623730951},"67":{"tf":1.4142135623730951},"73":{"tf":1.0},"82":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}}},"p":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"r":{"df":2,"docs":{"18":{"tf":1.0},"66":{"tf":1.0}}}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"t":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"19":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"65":{"tf":1.0}}}}}}},"s":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"b":{"df":0,"docs":{},"l":{"df":5,"docs":{"13":{"tf":1.0},"14":{"tf":1.0},"62":{"tf":1.4142135623730951},"78":{"tf":1.7320508075688772},"91":{"tf":1.0}}}},"df":0,"docs":{}}},"t":{"df":1,"docs":{"22":{"tf":1.0}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":3,"docs":{"0":{"tf":1.0},"34":{"tf":1.0},"68":{"tf":1.0}}}}}}},"w":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"66":{"tf":1.0},"80":{"tf":1.0}}}}}},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"c":{"df":2,"docs":{"52":{"tf":1.0},"75":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":3,"docs":{"62":{"tf":1.4142135623730951},"63":{"tf":1.7320508075688772},"65":{"tf":1.0}},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"62":{"tf":1.0}}}},"i":{"df":0,"docs":{},"x":{"df":1,"docs":{"62":{"tf":1.4142135623730951}}}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":2,"docs":{"40":{"tf":1.0},"78":{"tf":1.0}}}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":2,"docs":{"68":{"tf":1.0},"70":{"tf":1.0}}}}},"r":{"a":{"df":0,"docs":{},"n":{"d":{"a":{"df":0,"docs":{},"o":{"df":1,"docs":{"47":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"52":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"r":{"df":3,"docs":{"18":{"tf":1.0},"65":{"tf":1.0},"75":{"tf":1.0}},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"92":{"tf":1.0}}}}}}}},"o":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"65":{"tf":1.4142135623730951}}}},"df":1,"docs":{"75":{"tf":1.0}}}}}},"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":7,"docs":{"33":{"tf":1.0},"50":{"tf":1.0},"65":{"tf":1.0},"66":{"tf":1.0},"67":{"tf":1.0},"71":{"tf":1.0},"8":{"tf":1.0}}}}}},"d":{"df":0,"docs":{},"u":{"c":{"df":5,"docs":{"18":{"tf":1.0},"48":{"tf":1.0},"49":{"tf":1.0},"65":{"tf":1.0},"66":{"tf":1.0}},"t":{"df":1,"docs":{"18":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"88":{"tf":1.0}}}}},"g":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"m":{"df":2,"docs":{"52":{"tf":1.0},"91":{"tf":1.0}}}},"df":0,"docs":{}}},"j":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":6,"docs":{"3":{"tf":1.0},"5":{"tf":1.0},"59":{"tf":1.0},"65":{"tf":1.4142135623730951},"82":{"tf":1.0},"91":{"tf":1.0}},"’":{"df":2,"docs":{"60":{"tf":1.0},"92":{"tf":1.0}}}}},"df":0,"docs":{}}},"o":{"df":0,"docs":{},"f":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"z":{"df":1,"docs":{"57":{"tf":2.449489742783178}}}}}},"df":2,"docs":{"52":{"tf":1.0},"65":{"tf":1.0}}}},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"68":{"tf":1.0}}}}}}},"v":{"df":0,"docs":{},"e":{"df":1,"docs":{"79":{"tf":1.0}}},"i":{"d":{"df":8,"docs":{"18":{"tf":2.23606797749979},"52":{"tf":1.0},"56":{"tf":1.0},"64":{"tf":1.7320508075688772},"66":{"tf":1.0},"76":{"tf":1.0},"79":{"tf":1.4142135623730951},"91":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"x":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"75":{"tf":1.0}}}}}}},"u":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"c":{"df":2,"docs":{"51":{"tf":1.4142135623730951},"64":{"tf":1.0}}},"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"df":1,"docs":{"19":{"tf":1.0}}}}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":1,"docs":{"63":{"tf":1.4142135623730951}}}},"r":{"df":0,"docs":{},"g":{"a":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"=":{"6":{"1":{"4":{"4":{"/":{"3":{"1":{"4":{"5":{"7":{"2":{"8":{"df":1,"docs":{"57":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"s":{"df":5,"docs":{"16":{"tf":1.0},"17":{"tf":1.0},"30":{"tf":1.0},"52":{"tf":1.0},"75":{"tf":1.0}}}}}},"s":{"df":0,"docs":{},"h":{"df":1,"docs":{"63":{"tf":1.0}}}}},"v":{"df":0,"docs":{},"m":{"df":25,"docs":{"0":{"tf":1.4142135623730951},"13":{"tf":1.0},"14":{"tf":1.4142135623730951},"16":{"tf":1.0},"18":{"tf":1.0},"24":{"tf":1.0},"25":{"tf":1.0},"27":{"tf":1.0},"28":{"tf":1.0},"35":{"tf":1.0},"39":{"tf":1.0},"4":{"tf":1.4142135623730951},"48":{"tf":1.0},"52":{"tf":1.0},"55":{"tf":1.0},"70":{"tf":1.0},"71":{"tf":1.0},"72":{"tf":1.0},"73":{"tf":2.0},"74":{"tf":1.4142135623730951},"75":{"tf":3.0},"76":{"tf":1.0},"79":{"tf":1.4142135623730951},"91":{"tf":1.0},"92":{"tf":1.0}}}},"y":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"52":{"tf":1.0}}}}}}}},"q":{"df":0,"docs":{},"u":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"64":{"tf":1.0}}}},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"59":{"tf":1.0}}}}}}},"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"k":{"df":1,"docs":{"60":{"tf":1.0}}}},"df":0,"docs":{}}}},"r":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":1,"docs":{"18":{"tf":1.4142135623730951}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"65":{"tf":1.0}}}},"df":0,"docs":{}}}}},"w":{"df":1,"docs":{"18":{"tf":1.0}}}},"df":0,"docs":{},"e":{"a":{"d":{"a":{"b":{"df":0,"docs":{},"l":{"df":2,"docs":{"61":{"tf":1.0},"64":{"tf":1.0}}}},"df":0,"docs":{}},"df":5,"docs":{"1":{"tf":1.0},"34":{"tf":1.0},"40":{"tf":1.0},"61":{"tf":1.0},"65":{"tf":1.0}},"m":{"df":0,"docs":{},"e":{".":{"df":0,"docs":{},"m":{"d":{"df":2,"docs":{"10":{"tf":1.0},"60":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"z":{"df":2,"docs":{"72":{"tf":1.0},"91":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":7,"docs":{"18":{"tf":1.0},"32":{"tf":1.0},"43":{"tf":1.0},"52":{"tf":1.0},"69":{"tf":1.0},"70":{"tf":1.0},"91":{"tf":1.0}}}}}},"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":1,"docs":{"39":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"m":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"d":{"df":2,"docs":{"69":{"tf":1.0},"88":{"tf":1.0}}},"df":0,"docs":{}}}}}}},"d":{"df":0,"docs":{},"u":{"c":{"df":1,"docs":{"75":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"f":{"_":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"57":{"tf":2.449489742783178}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":7,"docs":{"39":{"tf":1.0},"4":{"tf":1.0},"6":{"tf":1.0},"60":{"tf":1.0},"78":{"tf":1.0},"79":{"tf":1.0},"8":{"tf":1.0}}}}},"g":{"a":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"50":{"tf":1.4142135623730951}},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"18":{"tf":1.0}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":2,"docs":{"13":{"tf":1.0},"75":{"tf":1.4142135623730951}}}}},"u":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"52":{"tf":1.0}}}},"df":0,"docs":{}},"r":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"65":{"tf":1.0}}}}}},"df":0,"docs":{}}}},"j":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"65":{"tf":1.0}}}},"df":0,"docs":{}}},"l":{"a":{"df":0,"docs":{},"t":{"df":3,"docs":{"24":{"tf":1.0},"40":{"tf":1.4142135623730951},"49":{"tf":1.4142135623730951}}}},"df":1,"docs":{"18":{"tf":1.0}},"e":{"a":{"df":0,"docs":{},"s":{"df":4,"docs":{"68":{"tf":1.4142135623730951},"7":{"tf":1.7320508075688772},"71":{"tf":1.4142135623730951},"92":{"tf":1.7320508075688772}}}},"df":0,"docs":{}},"i":{"df":2,"docs":{"66":{"tf":1.0},"92":{"tf":1.0}}},"o":{"c":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"74":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"x":{".":{"df":0,"docs":{},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"k":{"a":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{".":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":1,"docs":{"23":{"tf":1.0}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":1,"docs":{"23":{"tf":1.7320508075688772}}}},"o":{"df":0,"docs":{},"v":{"df":3,"docs":{"49":{"tf":1.0},"75":{"tf":1.0},"79":{"tf":1.0}}}}},"p":{"df":0,"docs":{},"l":{"a":{"c":{"df":1,"docs":{"90":{"tf":1.7320508075688772}}},"df":0,"docs":{}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":1,"docs":{"80":{"tf":1.0}}}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":2,"docs":{"54":{"tf":1.0},"63":{"tf":1.0}}}}}}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":1,"docs":{"52":{"tf":1.0}},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":2,"docs":{"66":{"tf":1.0},"67":{"tf":1.0}}}}}}},"o":{"d":{"df":0,"docs":{},"u":{"c":{"df":1,"docs":{"68":{"tf":2.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"q":{"df":0,"docs":{},"u":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":4,"docs":{"18":{"tf":1.0},"32":{"tf":1.0},"33":{"tf":1.7320508075688772},"63":{"tf":1.7320508075688772}}}}},"i":{"df":0,"docs":{},"r":{"df":11,"docs":{"18":{"tf":1.0},"53":{"tf":1.0},"54":{"tf":1.0},"6":{"tf":1.0},"64":{"tf":1.0},"65":{"tf":1.0},"71":{"tf":1.0},"74":{"tf":1.0},"75":{"tf":1.0},"77":{"tf":1.0},"82":{"tf":1.0}}}}}},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"c":{".":{"df":0,"docs":{},"j":{"df":1,"docs":{"81":{"tf":1.0}}}},"df":57,"docs":{"10":{"tf":1.7320508075688772},"11":{"tf":2.0},"12":{"tf":1.4142135623730951},"13":{"tf":1.0},"14":{"tf":1.0},"15":{"tf":1.0},"16":{"tf":1.0},"17":{"tf":1.0},"18":{"tf":2.23606797749979},"19":{"tf":1.4142135623730951},"20":{"tf":1.4142135623730951},"21":{"tf":1.4142135623730951},"22":{"tf":1.4142135623730951},"23":{"tf":1.7320508075688772},"24":{"tf":1.0},"25":{"tf":1.0},"26":{"tf":1.4142135623730951},"27":{"tf":1.7320508075688772},"28":{"tf":1.0},"29":{"tf":1.4142135623730951},"30":{"tf":1.0},"31":{"tf":1.0},"32":{"tf":1.4142135623730951},"33":{"tf":1.7320508075688772},"34":{"tf":1.0},"35":{"tf":1.0},"36":{"tf":1.0},"37":{"tf":1.0},"38":{"tf":1.0},"39":{"tf":1.0},"4":{"tf":2.449489742783178},"40":{"tf":1.0},"41":{"tf":1.0},"42":{"tf":1.0},"43":{"tf":1.0},"44":{"tf":1.0},"45":{"tf":1.0},"46":{"tf":1.0},"47":{"tf":1.0},"48":{"tf":1.0},"49":{"tf":1.0},"5":{"tf":2.449489742783178},"50":{"tf":1.4142135623730951},"51":{"tf":1.0},"52":{"tf":1.0},"6":{"tf":1.4142135623730951},"61":{"tf":1.4142135623730951},"67":{"tf":2.0},"68":{"tf":1.4142135623730951},"7":{"tf":2.0},"71":{"tf":1.0},"8":{"tf":1.4142135623730951},"82":{"tf":1.0},"88":{"tf":1.0},"9":{"tf":1.0},"90":{"tf":1.7320508075688772},"92":{"tf":1.0}}},"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"18":{"tf":1.0}}}},"v":{"df":1,"docs":{"18":{"tf":1.0}}}},"u":{"df":0,"docs":{},"r":{"c":{"df":1,"docs":{"2":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}},"t":{"df":1,"docs":{"32":{"tf":1.0}},"r":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"t":{"df":3,"docs":{"41":{"tf":1.0},"46":{"tf":1.0},"89":{"tf":1.0}}}},"df":0,"docs":{}}}},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":2,"docs":{"69":{"tf":1.0},"79":{"tf":1.7320508075688772}}}}}},"t":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"91":{"tf":1.0}}}}},"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"d":{"a":{"df":0,"docs":{},"t":{"a":{"df":1,"docs":{"46":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":7,"docs":{"35":{"tf":1.0},"38":{"tf":1.0},"41":{"tf":1.0},"44":{"tf":1.0},"45":{"tf":1.0},"46":{"tf":1.4142135623730951},"51":{"tf":2.449489742783178}}}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":4,"docs":{"13":{"tf":1.0},"14":{"tf":1.0},"46":{"tf":1.4142135623730951},"57":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"df":1,"docs":{"65":{"tf":1.0}}}},"v":{"df":38,"docs":{"0":{"tf":1.7320508075688772},"10":{"tf":1.0},"24":{"tf":1.0},"3":{"tf":1.0},"34":{"tf":1.0},"37":{"tf":1.0},"40":{"tf":1.0},"41":{"tf":1.0},"43":{"tf":2.23606797749979},"46":{"tf":1.0},"5":{"tf":2.23606797749979},"50":{"tf":1.0},"52":{"tf":1.0},"53":{"tf":2.23606797749979},"54":{"tf":2.0},"55":{"tf":1.7320508075688772},"56":{"tf":1.4142135623730951},"57":{"tf":1.4142135623730951},"58":{"tf":1.0},"59":{"tf":1.0},"6":{"tf":1.0},"62":{"tf":1.4142135623730951},"65":{"tf":1.0},"66":{"tf":1.4142135623730951},"67":{"tf":1.0},"68":{"tf":1.0},"69":{"tf":2.449489742783178},"71":{"tf":1.0},"73":{"tf":2.23606797749979},"74":{"tf":1.0},"75":{"tf":1.4142135623730951},"76":{"tf":2.6457513110645907},"77":{"tf":1.0},"79":{"tf":2.8284271247461903},"80":{"tf":1.7320508075688772},"82":{"tf":1.7320508075688772},"9":{"tf":1.7320508075688772},"91":{"tf":1.4142135623730951}},"e":{"_":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{"_":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"x":{"=":{"$":{"df":0,"docs":{},"{":{"df":0,"docs":{},"p":{"df":0,"docs":{},"w":{"d":{"df":0,"docs":{},"}":{"/":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"82":{"tf":1.0}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":1,"docs":{"82":{"tf":1.0}}}}}}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"91":{"tf":1.0}}}}}}},"w":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"91":{"tf":1.0}}}}}}},"i":{"df":0,"docs":{},"s":{"c":{"df":5,"docs":{"52":{"tf":1.0},"66":{"tf":1.0},"67":{"tf":1.0},"72":{"tf":1.0},"75":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"o":{"a":{"d":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"p":{"df":3,"docs":{"52":{"tf":1.0},"91":{"tf":1.7320508075688772},"92":{"tf":2.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"32":{"tf":1.0}}}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":0,"docs":{},"p":{"df":1,"docs":{"49":{"tf":1.4142135623730951}}}}}},"o":{"df":0,"docs":{},"m":{"df":1,"docs":{"79":{"tf":1.0}}},"t":{"df":1,"docs":{"54":{"tf":1.0}}}},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":1,"docs":{"92":{"tf":1.0}}}}}},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":4,"docs":{"0":{"tf":1.0},"37":{"tf":1.7320508075688772},"61":{"tf":1.0},"63":{"tf":1.4142135623730951}}}},"n":{"df":10,"docs":{"0":{"tf":1.0},"3":{"tf":1.0},"51":{"tf":1.0},"53":{"tf":1.4142135623730951},"56":{"tf":1.0},"61":{"tf":1.4142135623730951},"62":{"tf":1.0},"77":{"tf":1.0},"81":{"tf":1.0},"88":{"tf":1.0}},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":7,"docs":{"53":{"tf":2.0},"54":{"tf":1.7320508075688772},"55":{"tf":1.0},"56":{"tf":1.4142135623730951},"57":{"tf":1.4142135623730951},"79":{"tf":2.449489742783178},"80":{"tf":1.4142135623730951}}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":14,"docs":{"0":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"35":{"tf":2.23606797749979},"40":{"tf":1.0},"43":{"tf":1.4142135623730951},"53":{"tf":1.0},"55":{"tf":1.4142135623730951},"73":{"tf":1.7320508075688772},"74":{"tf":1.0},"75":{"tf":1.0},"76":{"tf":2.0},"79":{"tf":1.0},"80":{"tf":1.0}},"e":{":":{":":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":1,"docs":{"57":{"tf":1.7320508075688772}},"i":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{":":{":":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"c":{"df":1,"docs":{"57":{"tf":2.449489742783178}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"s":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"g":{"=":{"df":0,"docs":{},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"k":{"a":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{"=":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"c":{"df":1,"docs":{"55":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}},"r":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"=":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"c":{"df":2,"docs":{"55":{"tf":1.0},"57":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}}}},"df":1,"docs":{"55":{"tf":1.0}}}}}},"df":7,"docs":{"52":{"tf":3.1622776601683795},"54":{"tf":1.0},"62":{"tf":1.7320508075688772},"64":{"tf":1.0},"71":{"tf":1.0},"83":{"tf":1.4142135623730951},"91":{"tf":1.0}}}}},"v":{"6":{"4":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"a":{"c":{"b":{"df":1,"docs":{"71":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"s":{"a":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":2,"docs":{"52":{"tf":1.0},"92":{"tf":1.0}}}},"m":{"df":0,"docs":{},"e":{"df":7,"docs":{"18":{"tf":1.4142135623730951},"52":{"tf":1.0},"64":{"tf":1.0},"68":{"tf":1.0},"75":{"tf":1.0},"80":{"tf":1.0},"87":{"tf":1.0}}}},"n":{"d":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"x":{"df":7,"docs":{"53":{"tf":1.7320508075688772},"54":{"tf":1.0},"55":{"tf":1.0},"56":{"tf":1.0},"57":{"tf":1.0},"75":{"tf":1.0},"79":{"tf":1.0}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"v":{"df":0,"docs":{},"e":{"df":1,"docs":{"43":{"tf":1.0}}}}},"c":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":1,"docs":{"91":{"tf":1.4142135623730951}}}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":3,"docs":{"52":{"tf":1.0},"71":{"tf":1.0},"82":{"tf":1.0}}}}}}},"d":{"df":0,"docs":{},"k":{"df":1,"docs":{"52":{"tf":1.4142135623730951}}}},"df":1,"docs":{"12":{"tf":1.0}},"e":{"a":{"df":0,"docs":{},"l":{"_":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"(":{"df":0,"docs":{},"f":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"g":{"df":1,"docs":{"57":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}},"m":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"52":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"43":{"tf":1.0}}}}}}}}}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"d":{"df":2,"docs":{"32":{"tf":1.0},"92":{"tf":1.0}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":2,"docs":{"0":{"tf":1.0},"34":{"tf":1.4142135623730951}}}}}},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"65":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"d":{"df":1,"docs":{"75":{"tf":1.0}}},"df":8,"docs":{"11":{"tf":1.0},"22":{"tf":1.0},"40":{"tf":1.0},"52":{"tf":1.0},"54":{"tf":1.0},"69":{"tf":1.0},"86":{"tf":1.0},"87":{"tf":1.0}}},"l":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":2,"docs":{"31":{"tf":1.0},"33":{"tf":2.23606797749979}},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"33":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}}},"m":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":5,"docs":{"0":{"tf":1.0},"64":{"tf":1.0},"72":{"tf":1.0},"78":{"tf":1.0},"79":{"tf":1.0}}}}},"df":0,"docs":{}},"n":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"65":{"tf":1.0}}}}},"t":{"df":1,"docs":{"80":{"tf":1.0}}}},"t":{"df":10,"docs":{"12":{"tf":1.0},"18":{"tf":1.0},"25":{"tf":1.0},"27":{"tf":1.0},"28":{"tf":1.0},"29":{"tf":1.0},"32":{"tf":1.4142135623730951},"33":{"tf":1.0},"70":{"tf":1.0},"79":{"tf":1.4142135623730951}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"s":{".":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"u":{"df":1,"docs":{"30":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}}}}},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"28":{"tf":1.7320508075688772}},"i":{"df":0,"docs":{},"z":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{".":{"df":0,"docs":{},"m":{"df":0,"docs":{},"o":{"d":{"df":1,"docs":{"29":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}}}},"u":{"df":0,"docs":{},"t":{"df":0,"docs":{},"p":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"31":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}}}}}}}}}},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"k":{"a":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{".":{"d":{"df":0,"docs":{},"e":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"m":{"df":1,"docs":{"26":{"tf":1.4142135623730951}}}}}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"y":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{".":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"s":{"df":1,"docs":{"27":{"tf":1.0}}}}},"df":0,"docs":{}}},"s":{"df":0,"docs":{},"t":{"a":{"c":{"df":0,"docs":{},"k":{"df":0,"docs":{},"s":{"df":1,"docs":{"27":{"tf":1.0}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":1,"docs":{"27":{"tf":1.4142135623730951}}}}}}}},"df":0,"docs":{}}}}}}}},"df":1,"docs":{"25":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}}}}}},"h":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":1,"docs":{"67":{"tf":1.4142135623730951}}}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":1,"docs":{"75":{"tf":1.0}}}},"w":{"df":2,"docs":{"65":{"tf":1.0},"75":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"n":{"df":1,"docs":{"65":{"tf":1.0}},"i":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"c":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":2,"docs":{"91":{"tf":1.0},"92":{"tf":1.0}}}}}}},"df":2,"docs":{"72":{"tf":1.0},"91":{"tf":1.0}}},"df":0,"docs":{}}}}}},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"r":{"df":4,"docs":{"18":{"tf":1.0},"33":{"tf":1.0},"70":{"tf":1.0},"75":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"90":{"tf":1.0}}}}}},"df":0,"docs":{}}},"p":{"df":0,"docs":{},"l":{"df":4,"docs":{"18":{"tf":1.0},"69":{"tf":1.0},"77":{"tf":1.0},"79":{"tf":1.0}},"i":{"df":1,"docs":{"79":{"tf":1.0}},"f":{"df":0,"docs":{},"i":{"df":2,"docs":{"18":{"tf":1.0},"79":{"tf":1.0}}}}}}}},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"l":{"df":6,"docs":{"29":{"tf":1.0},"35":{"tf":1.0},"5":{"tf":1.4142135623730951},"53":{"tf":1.0},"75":{"tf":1.0},"91":{"tf":1.0}}}}},"t":{"df":1,"docs":{"75":{"tf":1.0}}},"z":{"df":0,"docs":{},"e":{"df":15,"docs":{"0":{"tf":1.4142135623730951},"12":{"tf":1.7320508075688772},"13":{"tf":2.6457513110645907},"14":{"tf":2.6457513110645907},"27":{"tf":2.0},"35":{"tf":1.4142135623730951},"39":{"tf":1.7320508075688772},"40":{"tf":1.0},"41":{"tf":1.0},"43":{"tf":1.0},"45":{"tf":1.0},"46":{"tf":1.0},"70":{"tf":1.4142135623730951},"89":{"tf":1.7320508075688772},"92":{"tf":1.0}}}}},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":1,"docs":{"65":{"tf":1.4142135623730951}}},"w":{"df":1,"docs":{"75":{"tf":1.7320508075688772}},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"75":{"tf":1.0}}}}}}},"m":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":4,"docs":{"13":{"tf":1.0},"14":{"tf":1.0},"50":{"tf":1.0},"52":{"tf":1.0}}}},"r":{"df":0,"docs":{},"t":{"df":3,"docs":{"4":{"tf":1.0},"66":{"tf":1.0},"75":{"tf":1.0}}}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"f":{"df":0,"docs":{},"t":{"df":0,"docs":{},"w":{"a":{"df":0,"docs":{},"r":{"df":3,"docs":{"52":{"tf":1.0},"59":{"tf":1.0},"65":{"tf":1.0}}}},"df":0,"docs":{}}}},"l":{"c":{"df":19,"docs":{"11":{"tf":1.0},"15":{"tf":2.23606797749979},"18":{"tf":2.23606797749979},"24":{"tf":1.0},"33":{"tf":1.0},"39":{"tf":1.0},"50":{"tf":2.0},"6":{"tf":1.0},"66":{"tf":1.4142135623730951},"67":{"tf":1.0},"68":{"tf":1.4142135623730951},"72":{"tf":1.4142135623730951},"78":{"tf":1.0},"79":{"tf":1.0},"8":{"tf":1.7320508075688772},"85":{"tf":1.0},"88":{"tf":1.0},"90":{"tf":1.7320508075688772},"92":{"tf":1.0}}},"df":0,"docs":{},"e":{"df":1,"docs":{"65":{"tf":1.0}}},"i":{"d":{"df":25,"docs":{"0":{"tf":1.4142135623730951},"1":{"tf":1.4142135623730951},"18":{"tf":2.23606797749979},"21":{"tf":1.7320508075688772},"22":{"tf":1.0},"3":{"tf":1.0},"34":{"tf":1.4142135623730951},"36":{"tf":1.7320508075688772},"39":{"tf":1.0},"4":{"tf":2.0},"43":{"tf":1.0},"5":{"tf":1.0},"52":{"tf":1.7320508075688772},"6":{"tf":1.7320508075688772},"60":{"tf":1.0},"65":{"tf":1.0},"66":{"tf":1.7320508075688772},"67":{"tf":1.4142135623730951},"78":{"tf":2.0},"79":{"tf":1.7320508075688772},"8":{"tf":1.0},"85":{"tf":1.0},"88":{"tf":1.4142135623730951},"91":{"tf":2.0},"92":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"52":{"tf":1.0}}}}},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"52":{"tf":1.0}}},"i":{"df":0,"docs":{},"m":{"df":3,"docs":{"53":{"tf":1.0},"55":{"tf":1.0},"62":{"tf":1.0}}}}},"w":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"75":{"tf":1.0}}}}}}}},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"65":{"tf":1.0}}}}}}},"r":{"c":{"df":10,"docs":{"10":{"tf":1.4142135623730951},"17":{"tf":1.0},"18":{"tf":1.0},"33":{"tf":1.4142135623730951},"54":{"tf":1.0},"59":{"tf":1.0},"67":{"tf":1.4142135623730951},"77":{"tf":1.0},"82":{"tf":1.0},"92":{"tf":1.0}}},"df":0,"docs":{}}}},"p":{"a":{"c":{"df":0,"docs":{},"e":{"df":1,"docs":{"13":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"df":0,"docs":{},"e":{"c":{"df":2,"docs":{"79":{"tf":1.4142135623730951},"80":{"tf":1.4142135623730951}},"i":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"71":{"tf":1.0}}}},"df":0,"docs":{},"f":{"df":10,"docs":{"25":{"tf":1.0},"27":{"tf":1.0},"28":{"tf":1.0},"32":{"tf":2.449489742783178},"33":{"tf":1.0},"52":{"tf":1.0},"71":{"tf":1.0},"72":{"tf":1.0},"75":{"tf":1.0},"79":{"tf":1.4142135623730951}},"i":{"df":3,"docs":{"15":{"tf":1.0},"16":{"tf":1.0},"30":{"tf":1.0}}}}}},"df":0,"docs":{},"e":{"d":{"df":3,"docs":{"1":{"tf":1.0},"75":{"tf":1.4142135623730951},"91":{"tf":1.0}}},"df":0,"docs":{}}}},"r":{"c":{"/":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"/":{"b":{"a":{"df":0,"docs":{},"r":{".":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{":":{"b":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"18":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":1,"docs":{"18":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"t":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"76":{"tf":1.0}}}},"c":{"df":0,"docs":{},"k":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"z":{"df":1,"docs":{"13":{"tf":1.0}}}}}},"df":6,"docs":{"0":{"tf":1.0},"13":{"tf":2.8284271247461903},"27":{"tf":1.4142135623730951},"72":{"tf":1.0},"78":{"tf":1.0},"79":{"tf":1.0}}}},"df":0,"docs":{},"n":{"d":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"79":{"tf":1.0}}}}},"r":{"d":{"df":13,"docs":{"24":{"tf":2.0},"25":{"tf":1.0},"26":{"tf":1.0},"27":{"tf":1.0},"28":{"tf":1.0},"29":{"tf":1.0},"30":{"tf":1.0},"31":{"tf":1.0},"32":{"tf":1.0},"33":{"tf":1.0},"55":{"tf":1.0},"62":{"tf":1.0},"68":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"_":{"df":0,"docs":{},"i":{"d":{"df":1,"docs":{"51":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}}},"df":4,"docs":{"58":{"tf":1.0},"60":{"tf":1.4142135623730951},"72":{"tf":1.0},"85":{"tf":1.0}},"u":{"df":0,"docs":{},"p":{"df":3,"docs":{"13":{"tf":1.0},"14":{"tf":1.0},"75":{"tf":1.0}}}}}},"t":{"df":0,"docs":{},"e":{"df":5,"docs":{"51":{"tf":1.7320508075688772},"56":{"tf":1.0},"68":{"tf":1.0},"75":{"tf":1.0},"79":{"tf":1.4142135623730951}}},"i":{"c":{"df":4,"docs":{"14":{"tf":1.0},"68":{"tf":1.0},"70":{"tf":1.4142135623730951},"81":{"tf":1.0}}},"df":0,"docs":{}}}},"d":{"df":1,"docs":{"18":{"tf":1.4142135623730951}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"p":{"df":2,"docs":{"67":{"tf":1.0},"79":{"tf":1.0}}}},"i":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":1,"docs":{"18":{"tf":1.0}}}}},"o":{"c":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"65":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"g":{"df":1,"docs":{"79":{"tf":1.0}}}},"df":0,"docs":{}}},"r":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":1,"docs":{"65":{"tf":1.0}},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"w":{"a":{"df":0,"docs":{},"r":{"d":{"df":2,"docs":{"7":{"tf":1.0},"83":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"df":4,"docs":{"77":{"tf":2.0},"78":{"tf":1.0},"79":{"tf":1.0},"80":{"tf":1.7320508075688772}}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"52":{"tf":1.0}}}}}}},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":2,"docs":{"18":{"tf":1.0},"64":{"tf":1.0}}}},"p":{"df":1,"docs":{"53":{"tf":1.0}}}},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":3,"docs":{"37":{"tf":1.0},"43":{"tf":1.0},"69":{"tf":1.0}}}}}}},"u":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"18":{"tf":1.0}}}}}},"df":0,"docs":{}}},"u":{"d":{"df":0,"docs":{},"i":{"df":1,"docs":{"0":{"tf":1.0}}}},"df":0,"docs":{}},"y":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":2,"docs":{"64":{"tf":1.4142135623730951},"65":{"tf":1.0}}}}}},"u":{"b":{"df":0,"docs":{},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":2,"docs":{"63":{"tf":1.4142135623730951},"65":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"18":{"tf":1.0}}}}}}}}},"c":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"20":{"tf":1.0}},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"75":{"tf":1.0}}}}}}}},"df":0,"docs":{},"h":{"df":3,"docs":{"33":{"tf":1.4142135623730951},"52":{"tf":1.0},"64":{"tf":1.0}}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"i":{"df":2,"docs":{"18":{"tf":1.0},"65":{"tf":1.0}}}},"df":0,"docs":{}}}},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"80":{"tf":1.0}}}},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"49":{"tf":1.0}}}}}}},"p":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":4,"docs":{"18":{"tf":1.0},"37":{"tf":1.0},"39":{"tf":1.0},"43":{"tf":1.4142135623730951}}}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":17,"docs":{"18":{"tf":1.0},"21":{"tf":1.0},"23":{"tf":1.0},"28":{"tf":1.0},"32":{"tf":1.0},"33":{"tf":1.0},"4":{"tf":1.0},"40":{"tf":1.0},"42":{"tf":1.0},"52":{"tf":1.4142135623730951},"68":{"tf":1.0},"7":{"tf":1.0},"82":{"tf":1.4142135623730951},"85":{"tf":2.0},"86":{"tf":1.7320508075688772},"87":{"tf":1.4142135623730951},"88":{"tf":1.7320508075688772}}}},"s":{"df":2,"docs":{"18":{"tf":1.0},"57":{"tf":1.0}}}}}},"r":{"df":0,"docs":{},"e":{"df":1,"docs":{"18":{"tf":1.0}}}}},"w":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"80":{"tf":1.0}}}},"df":0,"docs":{}},"y":{"df":1,"docs":{"71":{"tf":1.0}},"m":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":2,"docs":{"18":{"tf":1.4142135623730951},"64":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}},"s":{"c":{"a":{"df":0,"docs":{},"l":{"df":2,"docs":{"57":{"tf":1.0},"76":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":1,"docs":{"7":{"tf":1.0}}}}}}}},"t":{"a":{"df":0,"docs":{},"k":{"df":0,"docs":{},"e":{"df":3,"docs":{"18":{"tf":1.0},"66":{"tf":1.0},"80":{"tf":1.0}}}},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":12,"docs":{"1":{"tf":1.4142135623730951},"4":{"tf":1.0},"68":{"tf":1.0},"71":{"tf":1.4142135623730951},"72":{"tf":1.7320508075688772},"73":{"tf":2.0},"74":{"tf":2.0},"75":{"tf":1.4142135623730951},"76":{"tf":1.4142135623730951},"78":{"tf":1.0},"81":{"tf":1.0},"82":{"tf":2.23606797749979}}}}}}},"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"h":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"52":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"m":{"df":1,"docs":{"66":{"tf":1.0}},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"g":{"df":1,"docs":{"35":{"tf":1.0}}}}}}}}}},"s":{"df":0,"docs":{},"t":{"df":8,"docs":{"51":{"tf":1.4142135623730951},"61":{"tf":1.4142135623730951},"63":{"tf":1.0},"77":{"tf":3.0},"78":{"tf":1.0},"79":{"tf":3.7416573867739413},"80":{"tf":3.3166247903554},"82":{"tf":1.0}}}}},"h":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"k":{"df":2,"docs":{"4":{"tf":1.0},"80":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":2,"docs":{"35":{"tf":1.0},"40":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"62":{"tf":1.0}}}},"’":{"df":1,"docs":{"0":{"tf":1.0}}}}}},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":5,"docs":{"11":{"tf":1.0},"18":{"tf":1.0},"5":{"tf":1.0},"62":{"tf":1.0},"64":{"tf":1.4142135623730951}}}},"r":{"d":{"df":2,"docs":{"20":{"tf":1.0},"64":{"tf":1.0}}},"df":0,"docs":{}}},"o":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":2,"docs":{"11":{"tf":1.0},"18":{"tf":1.0}}}},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":1,"docs":{"72":{"tf":1.0}}}}}},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":2,"docs":{"67":{"tf":1.0},"79":{"tf":1.0}}}}}}},"u":{"df":6,"docs":{"18":{"tf":1.0},"32":{"tf":1.0},"40":{"tf":1.0},"43":{"tf":1.0},"72":{"tf":1.0},"80":{"tf":1.0}},"m":{"b":{"df":1,"docs":{"61":{"tf":1.0}}},"df":0,"docs":{}}}},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"52":{"tf":1.0}}}}}}},"m":{"df":0,"docs":{},"e":{"df":7,"docs":{"12":{"tf":1.7320508075688772},"18":{"tf":3.0},"41":{"tf":1.0},"46":{"tf":1.0},"48":{"tf":1.0},"49":{"tf":1.0},"75":{"tf":1.4142135623730951}},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"92":{"tf":1.0}}}}}}},"n":{"df":0,"docs":{},"i":{"df":1,"docs":{"80":{"tf":1.0}}}},"p":{"df":3,"docs":{"11":{"tf":1.0},"35":{"tf":1.0},"77":{"tf":1.0}}}},"m":{"df":0,"docs":{},"p":{"/":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"19":{"tf":1.0}}}}}},"df":0,"docs":{}}},"o":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":2,"docs":{"62":{"tf":1.0},"77":{"tf":1.0}}}}}},"o":{"df":0,"docs":{},"l":{"df":10,"docs":{"18":{"tf":1.0},"20":{"tf":2.0},"21":{"tf":1.0},"22":{"tf":1.0},"23":{"tf":1.0},"52":{"tf":1.0},"65":{"tf":1.0},"77":{"tf":1.0},"79":{"tf":1.4142135623730951},"89":{"tf":1.4142135623730951}},"k":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"21":{"tf":1.7320508075688772}}}}}}},"t":{"a":{"df":0,"docs":{},"l":{"df":2,"docs":{"13":{"tf":1.4142135623730951},"14":{"tf":1.0}}}},"df":0,"docs":{}}},"r":{"a":{"c":{"df":0,"docs":{},"e":{"df":2,"docs":{"55":{"tf":2.23606797749979},"57":{"tf":3.0}}}},"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"13":{"tf":1.0}},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"52":{"tf":1.0}}}}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"69":{"tf":1.0}}}},"n":{"df":0,"docs":{},"s":{"a":{"c":{"df":0,"docs":{},"t":{"df":2,"docs":{"43":{"tf":1.0},"80":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"t":{"df":7,"docs":{"34":{"tf":1.0},"36":{"tf":1.0},"39":{"tf":1.0},"43":{"tf":1.0},"47":{"tf":1.0},"75":{"tf":1.0},"86":{"tf":1.0}}}},"df":0,"docs":{}}}},"p":{"df":3,"docs":{"0":{"tf":1.0},"39":{"tf":1.0},"40":{"tf":1.0}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"e":{"df":1,"docs":{"69":{"tf":1.0}}}},"i":{"df":2,"docs":{"62":{"tf":1.0},"64":{"tf":1.0}},"v":{"df":0,"docs":{},"i":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"70":{"tf":1.0}}}},"df":0,"docs":{}}}},"u":{"df":0,"docs":{},"e":{"df":2,"docs":{"79":{"tf":1.4142135623730951},"91":{"tf":1.0}}}}},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":1,"docs":{"75":{"tf":1.0}}}}},"w":{"df":0,"docs":{},"o":{"df":3,"docs":{"43":{"tf":1.0},"50":{"tf":1.0},"6":{"tf":1.0}}}},"y":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"75":{"tf":1.0}}},"df":0,"docs":{}}}}},"u":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"51":{"tf":2.0}}}}},"l":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"65":{"tf":1.0}}}}}},"n":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"n":{"df":1,"docs":{"70":{"tf":1.0}}}}}}},"c":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":1,"docs":{"65":{"tf":1.0}}}}}},"df":0,"docs":{}},"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":4,"docs":{"19":{"tf":1.0},"3":{"tf":1.0},"62":{"tf":1.0},"67":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":3,"docs":{"43":{"tf":1.0},"52":{"tf":1.0},"78":{"tf":1.0}}}},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"34":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"d":{"df":1,"docs":{"1":{"tf":1.0}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{},"f":{"a":{"df":0,"docs":{},"v":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"75":{"tf":1.0}}}}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"d":{"df":1,"docs":{"91":{"tf":1.0}}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":1,"docs":{"23":{"tf":1.0}}}}}}}},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"w":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"80":{"tf":1.0}}}},"df":0,"docs":{}}},"t":{"df":1,"docs":{"77":{"tf":1.4142135623730951}},"i":{"df":1,"docs":{"56":{"tf":1.0}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"s":{"df":1,"docs":{"7":{"tf":1.0}}}}}}},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"39":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"k":{"df":3,"docs":{"14":{"tf":1.0},"18":{"tf":1.0},"70":{"tf":1.0}}},"n":{"df":0,"docs":{},"k":{"df":1,"docs":{"18":{"tf":1.7320508075688772}}}}}},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"16":{"tf":1.0}}}}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"63":{"tf":1.0}}}},"r":{"df":0,"docs":{},"u":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"37":{"tf":1.0}}}}}}},"u":{"df":0,"docs":{},"s":{"df":1,"docs":{"40":{"tf":1.0}}}},"w":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"64":{"tf":1.0}}}},"df":0,"docs":{}}}},"p":{"d":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"62":{"tf":1.7320508075688772}}}},"df":0,"docs":{}},"df":3,"docs":{"1":{"tf":1.0},"52":{"tf":1.0},"91":{"tf":1.0}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"m":{"df":2,"docs":{"63":{"tf":1.0},"71":{"tf":1.0}}}},"df":0,"docs":{}}}}}},"s":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"19":{"tf":1.0}}}},"df":0,"docs":{},"g":{"df":4,"docs":{"11":{"tf":1.7320508075688772},"54":{"tf":1.7320508075688772},"57":{"tf":1.0},"70":{"tf":1.0}}}},"df":33,"docs":{"13":{"tf":1.7320508075688772},"14":{"tf":1.4142135623730951},"15":{"tf":1.0},"16":{"tf":1.0},"17":{"tf":1.0},"18":{"tf":2.0},"25":{"tf":1.0},"27":{"tf":1.0},"30":{"tf":1.0},"31":{"tf":1.0},"40":{"tf":1.4142135623730951},"43":{"tf":1.7320508075688772},"48":{"tf":1.4142135623730951},"49":{"tf":1.0},"5":{"tf":1.0},"52":{"tf":1.4142135623730951},"53":{"tf":1.0},"55":{"tf":1.0},"61":{"tf":1.7320508075688772},"64":{"tf":1.7320508075688772},"65":{"tf":1.0},"66":{"tf":1.0},"67":{"tf":1.0},"68":{"tf":1.0},"69":{"tf":1.4142135623730951},"70":{"tf":1.0},"71":{"tf":2.0},"75":{"tf":1.0},"77":{"tf":1.0},"8":{"tf":1.0},"81":{"tf":1.0},"82":{"tf":1.0},"88":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":52,"docs":{"1":{"tf":1.0},"10":{"tf":1.0},"11":{"tf":1.0},"12":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"15":{"tf":1.0},"16":{"tf":1.0},"17":{"tf":1.0},"18":{"tf":1.0},"19":{"tf":1.0},"20":{"tf":1.0},"21":{"tf":1.0},"22":{"tf":1.0},"23":{"tf":1.0},"24":{"tf":1.0},"25":{"tf":1.0},"26":{"tf":1.0},"27":{"tf":1.0},"28":{"tf":1.0},"29":{"tf":1.0},"30":{"tf":1.0},"31":{"tf":1.0},"32":{"tf":1.0},"33":{"tf":1.0},"34":{"tf":1.0},"35":{"tf":1.0},"36":{"tf":1.0},"37":{"tf":1.0},"38":{"tf":1.0},"39":{"tf":1.0},"4":{"tf":1.7320508075688772},"40":{"tf":1.0},"41":{"tf":1.0},"42":{"tf":1.0},"43":{"tf":1.0},"44":{"tf":1.0},"45":{"tf":1.0},"46":{"tf":1.0},"47":{"tf":1.0},"48":{"tf":1.0},"49":{"tf":1.0},"5":{"tf":1.4142135623730951},"50":{"tf":1.0},"51":{"tf":1.0},"52":{"tf":1.4142135623730951},"6":{"tf":1.0},"7":{"tf":1.0},"70":{"tf":1.0},"78":{"tf":1.0},"8":{"tf":1.0},"9":{"tf":1.0}}}},"u":{"a":{"df":0,"docs":{},"l":{"df":3,"docs":{"18":{"tf":1.0},"43":{"tf":1.0},"53":{"tf":1.0}}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":2,"docs":{"79":{"tf":1.0},"80":{"tf":1.4142135623730951}}}}}},"v":{"0":{".":{"8":{".":{"0":{"df":1,"docs":{"92":{"tf":1.0}}},"df":0,"docs":{}},"df":1,"docs":{"4":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"df":0,"docs":{}},"1":{".":{"0":{".":{"0":{"df":1,"docs":{"92":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"d":{"df":4,"docs":{"12":{"tf":1.0},"39":{"tf":1.0},"48":{"tf":1.0},"75":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"u":{"df":8,"docs":{"13":{"tf":1.4142135623730951},"14":{"tf":1.4142135623730951},"26":{"tf":1.0},"27":{"tf":1.4142135623730951},"29":{"tf":1.0},"39":{"tf":1.0},"45":{"tf":1.0},"47":{"tf":1.0}},"e":{"_":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"d":{"(":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":1,"docs":{"57":{"tf":1.0}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"i":{"a":{"b":{"df":0,"docs":{},"l":{"df":5,"docs":{"13":{"tf":1.0},"51":{"tf":1.7320508075688772},"55":{"tf":1.0},"64":{"tf":1.0},"82":{"tf":1.0}}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"75":{"tf":1.0}}}}},"df":2,"docs":{"12":{"tf":1.0},"40":{"tf":1.0}},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"20":{"tf":1.0}}}}}}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"79":{"tf":1.0}}}}}}},"df":4,"docs":{"52":{"tf":1.0},"66":{"tf":1.0},"67":{"tf":1.0},"75":{"tf":1.4142135623730951}},"e":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"0":{"tf":1.0}}}}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":2,"docs":{"75":{"tf":1.0},"79":{"tf":1.0}},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"52":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":5,"docs":{"23":{"tf":1.0},"61":{"tf":1.0},"68":{"tf":1.0},"85":{"tf":2.23606797749979},"88":{"tf":2.23606797749979}}}}}}}},"i":{"a":{"df":10,"docs":{"50":{"tf":1.4142135623730951},"51":{"tf":1.0},"63":{"tf":1.0},"68":{"tf":1.4142135623730951},"7":{"tf":1.0},"70":{"tf":1.0},"71":{"tf":1.0},"73":{"tf":1.0},"80":{"tf":1.0},"82":{"tf":1.7320508075688772}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"df":1,"docs":{"51":{"tf":1.4142135623730951}}}},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"51":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":2,"docs":{"91":{"tf":1.7320508075688772},"92":{"tf":1.0}}}},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{".":{"df":0,"docs":{},"r":{"df":1,"docs":{"69":{"tf":1.0}}}},"df":1,"docs":{"69":{"tf":1.4142135623730951}}}}}},"u":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"67":{"tf":1.0}}}},"df":0,"docs":{}}}},"m":{"df":3,"docs":{"43":{"tf":1.0},"52":{"tf":1.4142135623730951},"75":{"tf":1.4142135623730951}}},"s":{"df":3,"docs":{"35":{"tf":1.4142135623730951},"5":{"tf":1.4142135623730951},"72":{"tf":1.0}}}},"w":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":3,"docs":{"57":{"tf":1.0},"69":{"tf":1.0},"71":{"tf":1.0}}}},"r":{"df":0,"docs":{},"m":{"df":1,"docs":{"0":{"tf":1.0}}},"n":{"df":6,"docs":{"0":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"18":{"tf":1.0},"41":{"tf":1.0},"43":{"tf":1.0}}}},"s":{"df":0,"docs":{},"m":{"df":4,"docs":{"7":{"tf":1.0},"75":{"tf":2.8284271247461903},"81":{"tf":1.0},"82":{"tf":2.0}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"75":{"tf":1.4142135623730951}}}}}}},"y":{"df":3,"docs":{"32":{"tf":1.0},"77":{"tf":1.0},"83":{"tf":1.0}}}},"df":0,"docs":{},"e":{"b":{"3":{"df":1,"docs":{"91":{"tf":1.0}}},"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"b":{"df":0,"docs":{},"m":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"75":{"tf":1.0}}}}}},"df":0,"docs":{}}}}},"df":1,"docs":{"91":{"tf":1.0}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":1,"docs":{"57":{"tf":2.449489742783178}}}}}},"l":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"df":4,"docs":{"0":{"tf":2.0},"1":{"tf":1.0},"2":{"tf":1.0},"3":{"tf":1.0}}}}},"df":0,"docs":{},"l":{"df":3,"docs":{"1":{"tf":1.0},"34":{"tf":1.0},"79":{"tf":1.0}}}},"’":{"d":{"df":2,"docs":{"52":{"tf":1.0},"65":{"tf":1.0}}},"df":0,"docs":{}}},"h":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":1,"docs":{"65":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":1,"docs":{"62":{"tf":1.0}}}}},"r":{"df":0,"docs":{},"e":{"a":{"df":1,"docs":{"32":{"tf":1.0}}},"df":0,"docs":{},"v":{"df":1,"docs":{"78":{"tf":1.0}}}}},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"65":{"tf":1.0}}}}}}},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":1,"docs":{"5":{"tf":1.0}}}}}},"i":{"df":0,"docs":{},"e":{"d":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"12":{"tf":1.0}}}}},"df":0,"docs":{}},"l":{"d":{"c":{"a":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"32":{"tf":2.23606797749979}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"n":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":2,"docs":{"65":{"tf":1.0},"7":{"tf":1.0}}}}},"df":0,"docs":{}},"s":{"df":0,"docs":{},"h":{"df":1,"docs":{"65":{"tf":1.4142135623730951}}}}},"o":{"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"’":{"df":1,"docs":{"91":{"tf":1.0}}}},"df":0,"docs":{}},"r":{"d":{"df":2,"docs":{"5":{"tf":1.0},"64":{"tf":1.0}}},"df":0,"docs":{},"k":{"df":7,"docs":{"0":{"tf":1.4142135623730951},"18":{"tf":1.4142135623730951},"43":{"tf":1.4142135623730951},"52":{"tf":1.0},"69":{"tf":1.0},"72":{"tf":1.0},"90":{"tf":1.0}},"l":{"df":0,"docs":{},"o":{"a":{"d":{"df":1,"docs":{"75":{"tf":1.7320508075688772}}},"df":0,"docs":{}},"df":0,"docs":{}}},"s":{"df":0,"docs":{},"p":{"a":{"c":{"df":1,"docs":{"62":{"tf":1.7320508075688772}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"l":{"d":{"df":1,"docs":{"11":{"tf":1.0}}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"39":{"tf":1.0}}}},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"w":{"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"11":{"tf":1.0}}}}}}}}}},"r":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"71":{"tf":1.0},"79":{"tf":1.0}}}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":7,"docs":{"40":{"tf":1.0},"41":{"tf":1.0},"46":{"tf":1.0},"64":{"tf":1.0},"75":{"tf":1.0},"79":{"tf":1.0},"88":{"tf":1.4142135623730951}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":2,"docs":{"52":{"tf":1.4142135623730951},"66":{"tf":1.0}}}}}}}}},"x":{"8":{"6":{"df":1,"docs":{"75":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{},"y":{"df":2,"docs":{"87":{"tf":1.4142135623730951},"89":{"tf":1.4142135623730951}}}},"y":{"df":0,"docs":{},"e":{"df":1,"docs":{"86":{"tf":1.0}}},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"f":{"df":1,"docs":{"65":{"tf":1.0}}}}}}},"’":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":1,"docs":{"61":{"tf":1.0}}}}}}},"u":{"df":0,"docs":{},"l":{"df":12,"docs":{"16":{"tf":1.0},"22":{"tf":1.0},"34":{"tf":1.0},"39":{"tf":1.7320508075688772},"5":{"tf":1.0},"50":{"tf":1.0},"6":{"tf":1.0},"66":{"tf":1.0},"67":{"tf":1.4142135623730951},"69":{"tf":1.7320508075688772},"72":{"tf":1.0},"86":{"tf":1.0}}}}},"z":{"df":1,"docs":{"12":{"tf":1.0}},"k":{"df":1,"docs":{"52":{"tf":1.0}}}}}},"title":{"root":{"2":{"4":{"df":0,"docs":{},"k":{"b":{"df":1,"docs":{"89":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}},"6":{"3":{"/":{"6":{"4":{"df":1,"docs":{"37":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"a":{"d":{"d":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{".":{"c":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"o":{"d":{"df":1,"docs":{"38":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{},"i":{"df":1,"docs":{"65":{"tf":1.0}}},"r":{"c":{"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"66":{"tf":1.0}}}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"f":{"a":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"16":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"s":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"86":{"tf":1.0}}}},"df":0,"docs":{}}}}},"u":{"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"c":{"df":1,"docs":{"1":{"tf":1.0}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"56":{"tf":1.0}}}},"df":0,"docs":{}}}}}},"b":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"7":{"tf":1.0}}}}},"df":0,"docs":{}}},"l":{"df":0,"docs":{},"o":{"b":{"b":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":1,"docs":{"49":{"tf":1.0}}}}}}},"df":0,"docs":{}},"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"df":1,"docs":{"49":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"u":{"df":0,"docs":{},"g":{"df":1,"docs":{"78":{"tf":1.0}}},"i":{"d":{"df":0,"docs":{},"l":{"df":1,"docs":{"10":{"tf":1.0}}}},"df":0,"docs":{},"l":{"d":{"df":1,"docs":{"68":{"tf":1.0}}},"df":0,"docs":{}}}}},"c":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"d":{"a":{"df":0,"docs":{},"t":{"a":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":1,"docs":{"41":{"tf":1.0}}}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"a":{"d":{"df":1,"docs":{"41":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"11":{"tf":1.0}}}},"o":{"d":{"df":0,"docs":{},"e":{"b":{"a":{"df":0,"docs":{},"s":{"df":1,"docs":{"62":{"tf":1.0}}}},"df":0,"docs":{}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":1,"docs":{"42":{"tf":1.0}}}}}},"df":1,"docs":{"35":{"tf":1.4142135623730951}}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"78":{"tf":1.0}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":4,"docs":{"22":{"tf":1.0},"66":{"tf":1.0},"69":{"tf":1.0},"81":{"tf":1.0}}}}}},"n":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"74":{"tf":1.0}}}}}}},"t":{"df":0,"docs":{},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":6,"docs":{"2":{"tf":1.0},"33":{"tf":1.0},"52":{"tf":1.0},"56":{"tf":1.0},"68":{"tf":1.0},"89":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"i":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"63":{"tf":1.0}},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"59":{"tf":1.0}}}}}}},"df":0,"docs":{}}}}}},"p":{"df":0,"docs":{},"u":{"df":1,"docs":{"74":{"tf":1.0}}}},"r":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"43":{"tf":1.0}},"e":{"2":{"df":1,"docs":{"43":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"81":{"tf":1.0}}}}}},"u":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"df":1,"docs":{"72":{"tf":1.0}}}}}}}},"d":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"p":{"df":1,"docs":{"88":{"tf":1.0}}}},"t":{"a":{"df":0,"docs":{},"o":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"44":{"tf":1.0}}}}}}}},"s":{"df":1,"docs":{"45":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{},"e":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"df":2,"docs":{"16":{"tf":1.0},"17":{"tf":1.0}}}}},"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"d":{"df":2,"docs":{"71":{"tf":1.0},"8":{"tf":1.0}}},"df":0,"docs":{}}},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"y":{"df":3,"docs":{"18":{"tf":1.0},"35":{"tf":1.0},"89":{"tf":1.0}}}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":1,"docs":{"58":{"tf":1.0}}}}}}}},"i":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"34":{"tf":1.0},"50":{"tf":1.0}},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":2,"docs":{"79":{"tf":1.0},"80":{"tf":1.0}}}}}}}},"i":{"c":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"47":{"tf":1.0}}}}}}},"df":0,"docs":{}}}}},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":1,"docs":{"90":{"tf":1.0}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":0,"docs":{},"s":{"c":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"82":{"tf":1.0}}}}}}}}},"df":0,"docs":{}}},"n":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"76":{"tf":1.0}}}}}}}},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"u":{"df":0,"docs":{},"m":{"df":1,"docs":{"78":{"tf":1.0}}}}}}}}},"v":{"df":0,"docs":{},"m":{"df":4,"docs":{"33":{"tf":1.0},"34":{"tf":1.0},"70":{"tf":1.0},"85":{"tf":1.0}}}},"x":{"a":{"df":0,"docs":{},"m":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":2,"docs":{"51":{"tf":1.0},"57":{"tf":1.0}}}}}},"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"22":{"tf":1.0}}}}}},"t":{"c":{"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":1,"docs":{"48":{"tf":1.0}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"f":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"89":{"tf":1.0}}}},"q":{"df":1,"docs":{"84":{"tf":1.0}}}},"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":2,"docs":{"39":{"tf":1.0},"40":{"tf":1.0}}}}}}},"df":0,"docs":{}}}},"g":{"a":{"df":1,"docs":{"37":{"tf":1.0}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"60":{"tf":1.0}}}},"u":{"df":0,"docs":{},"i":{"d":{"df":4,"docs":{"4":{"tf":1.0},"58":{"tf":1.0},"59":{"tf":1.0},"64":{"tf":1.0}}},"df":0,"docs":{}}}},"h":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"p":{"df":2,"docs":{"14":{"tf":1.0},"70":{"tf":1.0}}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"76":{"tf":1.0}}}}}},"i":{"d":{"df":1,"docs":{"23":{"tf":1.0}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":1,"docs":{"17":{"tf":1.0}}}},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"51":{"tf":1.0}}}}}}},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"51":{"tf":1.0}}}}},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"86":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"l":{"df":3,"docs":{"54":{"tf":1.0},"6":{"tf":1.0},"8":{"tf":1.0}}},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"56":{"tf":1.0}}}}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"g":{"df":0,"docs":{},"r":{"df":2,"docs":{"20":{"tf":1.0},"79":{"tf":1.0}}}},"r":{"df":0,"docs":{},"f":{"a":{"c":{"df":1,"docs":{"24":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"n":{"df":1,"docs":{"66":{"tf":1.0}}}}}}},"r":{"df":1,"docs":{"50":{"tf":1.0}}}},"j":{"df":0,"docs":{},"s":{"df":1,"docs":{"19":{"tf":1.0}},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"24":{"tf":1.0}}}}}},"l":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"89":{"tf":1.0}}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":2,"docs":{"12":{"tf":1.0},"33":{"tf":1.0}}}}}},"i":{"b":{"c":{"df":1,"docs":{"83":{"tf":1.0}}},"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":2,"docs":{"52":{"tf":1.0},"69":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"k":{"df":1,"docs":{"18":{"tf":1.0}}}}},"l":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{"df":2,"docs":{"12":{"tf":1.0},"71":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"g":{"df":1,"docs":{"55":{"tf":1.0}}}}},"m":{"a":{"df":0,"docs":{},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"61":{"tf":1.0}}}}}}}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":1,"docs":{"40":{"tf":1.0}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":2,"docs":{"40":{"tf":1.0},"70":{"tf":1.0}}}}}}},"l":{"df":0,"docs":{},"o":{"a":{"d":{"df":1,"docs":{"40":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}},"o":{"d":{"df":0,"docs":{},"e":{"df":1,"docs":{"50":{"tf":1.0}}}},"df":0,"docs":{}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"z":{"df":0,"docs":{},"e":{"df":1,"docs":{"40":{"tf":1.0}}}}},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":1,"docs":{"40":{"tf":1.0}}}}}}},"u":{"df":0,"docs":{},"s":{"df":0,"docs":{},"l":{"df":1,"docs":{"83":{"tf":1.0}}}}}},"n":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"5":{"tf":1.0}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"p":{"df":0,"docs":{},"m":{"df":2,"docs":{"19":{"tf":1.0},"9":{"tf":1.0}}}}},"o":{"b":{"df":0,"docs":{},"j":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":4,"docs":{"25":{"tf":1.0},"27":{"tf":1.0},"28":{"tf":1.0},"31":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{},"p":{"c":{"df":0,"docs":{},"o":{"d":{"df":1,"docs":{"87":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":2,"docs":{"12":{"tf":1.0},"72":{"tf":1.0}}}}}},"r":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"51":{"tf":1.0}}}}},"df":0,"docs":{},"g":{"a":{"df":0,"docs":{},"n":{"df":1,"docs":{"62":{"tf":1.0}}}},"df":0,"docs":{}}},"u":{"df":0,"docs":{},"t":{"df":0,"docs":{},"p":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"33":{"tf":1.0}}}}}}}},"p":{"a":{"c":{"df":0,"docs":{},"k":{"a":{"df":0,"docs":{},"g":{"df":2,"docs":{"19":{"tf":1.0},"9":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":2,"docs":{"73":{"tf":1.0},"76":{"tf":1.0}}}}}}},"c":{"df":1,"docs":{"48":{"tf":1.0}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"i":{"df":1,"docs":{"65":{"tf":1.0}}}},"df":0,"docs":{}},"k":{"a":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"n":{"d":{"a":{"df":0,"docs":{},"o":{"df":1,"docs":{"47":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"v":{"df":0,"docs":{},"m":{"df":2,"docs":{"73":{"tf":1.0},"75":{"tf":1.0}}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"g":{"a":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"50":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}},"l":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"40":{"tf":1.0}}}},"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"s":{"df":1,"docs":{"7":{"tf":1.0}}}},"df":0,"docs":{}}},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"x":{"df":1,"docs":{"23":{"tf":1.0}}}}},"p":{"df":0,"docs":{},"l":{"a":{"c":{"df":1,"docs":{"90":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"u":{"c":{"df":1,"docs":{"68":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"c":{"df":6,"docs":{"10":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.0},"67":{"tf":1.0},"7":{"tf":1.0},"90":{"tf":1.0}}},"df":0,"docs":{}},"u":{"df":0,"docs":{},"r":{"c":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}}}}},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":1,"docs":{"46":{"tf":1.0}}}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":1,"docs":{"46":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"v":{"df":6,"docs":{"5":{"tf":1.0},"53":{"tf":1.0},"69":{"tf":1.0},"73":{"tf":1.0},"76":{"tf":1.0},"9":{"tf":1.0}}}}}},"o":{"a":{"d":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"p":{"df":2,"docs":{"91":{"tf":1.0},"92":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":2,"docs":{"37":{"tf":1.0},"63":{"tf":1.0}}}},"n":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"53":{"tf":1.0}}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":2,"docs":{"35":{"tf":1.0},"73":{"tf":1.0}}}}}},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"52":{"tf":1.0}}}}}},"s":{"a":{"df":0,"docs":{},"n":{"d":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"x":{"df":1,"docs":{"53":{"tf":1.0}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"33":{"tf":1.0}}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"s":{".":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"u":{"df":1,"docs":{"30":{"tf":1.0}}}}}},"df":0,"docs":{}}}}},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"28":{"tf":1.0}},"i":{"df":0,"docs":{},"z":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{".":{"df":0,"docs":{},"m":{"df":0,"docs":{},"o":{"d":{"df":1,"docs":{"29":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}}}},"u":{"df":0,"docs":{},"t":{"df":0,"docs":{},"p":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"31":{"tf":1.0}}}},"df":0,"docs":{}}}}}}}}}}},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"k":{"a":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{".":{"d":{"df":0,"docs":{},"e":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"m":{"df":1,"docs":{"26":{"tf":1.0}}}}}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"y":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":1,"docs":{"27":{"tf":1.0}}}}}}}},"df":0,"docs":{}}}}}}}},"df":1,"docs":{"25":{"tf":1.0}}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}}}}}},"i":{"df":0,"docs":{},"z":{"df":0,"docs":{},"e":{"df":3,"docs":{"13":{"tf":1.0},"14":{"tf":1.0},"89":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"l":{"c":{"df":4,"docs":{"15":{"tf":1.0},"50":{"tf":1.0},"8":{"tf":1.0},"90":{"tf":1.0}}},"df":0,"docs":{},"i":{"d":{"df":4,"docs":{"21":{"tf":1.0},"36":{"tf":1.0},"78":{"tf":1.0},"88":{"tf":1.0}}},"df":0,"docs":{}}},"u":{"df":0,"docs":{},"r":{"c":{"df":1,"docs":{"10":{"tf":1.0}}},"df":0,"docs":{}}}},"t":{"a":{"c":{"df":0,"docs":{},"k":{"df":1,"docs":{"13":{"tf":1.0}}}},"df":0,"docs":{},"n":{"d":{"a":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"24":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"t":{"df":1,"docs":{"60":{"tf":1.0}}}},"t":{"df":0,"docs":{},"e":{"df":1,"docs":{"51":{"tf":1.0}}}}},"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"df":1,"docs":{"77":{"tf":1.0}}}}}}},"df":0,"docs":{}},"y":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":1,"docs":{"64":{"tf":1.0}}}}}},"u":{"df":0,"docs":{},"p":{"df":0,"docs":{},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":3,"docs":{"85":{"tf":1.0},"86":{"tf":1.0},"87":{"tf":1.0}}}}}}}}},"t":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":3,"docs":{"1":{"tf":1.0},"73":{"tf":1.0},"74":{"tf":1.0}}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":3,"docs":{"77":{"tf":1.0},"79":{"tf":1.0},"80":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":1,"docs":{"18":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":2,"docs":{"20":{"tf":1.0},"89":{"tf":1.0}},"k":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"21":{"tf":1.0}}}}}}}},"r":{"a":{"c":{"df":0,"docs":{},"e":{"df":1,"docs":{"55":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"u":{"df":0,"docs":{},"s":{"a":{"df":0,"docs":{},"g":{"df":2,"docs":{"11":{"tf":1.0},"54":{"tf":1.0}}}},"df":1,"docs":{"61":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"4":{"tf":1.0}}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"80":{"tf":1.0}}}}}},"v":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"51":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":2,"docs":{"85":{"tf":1.0},"88":{"tf":1.0}}}}}}}},"i":{"a":{"df":2,"docs":{"50":{"tf":1.0},"82":{"tf":1.0}}},"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"91":{"tf":1.0}}}}}}},"s":{"df":2,"docs":{"35":{"tf":1.0},"5":{"tf":1.0}}}},"w":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"m":{"df":1,"docs":{"82":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"df":1,"docs":{"0":{"tf":1.0}}}}},"df":0,"docs":{}}},"i":{"df":0,"docs":{},"l":{"d":{"c":{"a":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"32":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":1,"docs":{"88":{"tf":1.0}}}}}}},"x":{"df":0,"docs":{},"y":{"df":2,"docs":{"87":{"tf":1.0},"89":{"tf":1.0}}}},"y":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":1,"docs":{"39":{"tf":1.0}}}}}}}},"lang":"English","pipeline":["trimmer","stopWordFilter","stemmer"],"ref":"id","version":"0.9.5"},"results_options":{"limit_results":30,"teaser_word_count":30},"search_options":{"bool":"OR","expand":true,"fields":{"body":{"boost":1},"breadcrumbs":{"boost":1},"title":{"boost":2}}}}')); \ No newline at end of file diff --git a/docs/searchindex-c7304031.js b/docs/searchindex-c7304031.js deleted file mode 100644 index fb2f6ae..0000000 --- a/docs/searchindex-c7304031.js +++ /dev/null @@ -1 +0,0 @@ -window.search = Object.assign(window.search, JSON.parse('{"doc_urls":["welcome.html#welcome","welcome.html#target-audience","welcome.html#other-polkadot-contracts-resources","welcome.html#about","user_guide.html#resolc-user-guide","user_guide.html#revive-vs-resolc-nomenclature","user_guide/installation.html#installation","user_guide/installation.html#resolc-binary-releases","user_guide/installation.html#installing-the-solc-dependency","user_guide/installation.html#revive-npm-package","user_guide/installation.html#buidling-resolc-from-source","user_guide/cli.html#cli-usage","user_guide/cli.html#llvm-optimization-levels","user_guide/cli.html#stack-size","user_guide/cli.html#heap-size","user_guide/cli.html#solc","user_guide/cli.html#debug-artifacts","user_guide/cli.html#debug-info","user_guide/cli.html#deploy-time-linking","user_guide/js.html#js-npm-package","user_guide/tooling.html#tooling-integration","user_guide/tooling.html#solidity-toolkits","user_guide/tooling.html#compiler-explorer","user_guide/tooling.html#remix-ide","user_guide/std_json.html#standard-json-interface","user_guide/std_json.html#the-settingspolkavm-object","user_guide/std_json.html#settingspolkavmdebuginformation","user_guide/std_json.html#the-settingspolkavmmemoryconfig-object","user_guide/std_json.html#the-settingsoptimizer-object","user_guide/std_json.html#settingsoptimizermode","user_guide/std_json.html#settingsllvmarguments","user_guide/differences.html#differences-to-evm","user_guide/differences.html#deploy-code-vs-runtime-code","user_guide/differences.html#solidity","user_guide/differences.html#the-6364-gas-rule","user_guide/differences.html#addresscreationcode","user_guide/differences.html#yul-functions","user_guide/differences.html#mload-mstore-msize-mcopy-memory-related-functions","user_guide/differences.html#calldataload-calldatacopy","user_guide/differences.html#codecopy","user_guide/differences.html#create-create2","user_guide/differences.html#dataoffset","user_guide/differences.html#datasize","user_guide/differences.html#revert-return","user_guide/differences.html#prevrandao-difficulty","user_guide/differences.html#pc-extcodecopy","user_guide/differences.html#blobhash-blobbasefee","user_guide/differences.html#difference-regarding-the-solc-via-ir-mode","user_guide/differences.html#example-state-variable-initialization-order-in-inheritance","user_guide/rust_libraries.html#rust-contract-libraries","revive_runner.html#revive-runner-sandbox","revive_runner.html#installation-and-usage","revive_runner.html#trace-logs","revive_runner.html#automatic-contract-instantiation","revive_runner.html#example","developer_guide.html#developer-guide","developer_guide/contributing.html#contributor-guide","developer_guide/contributing.html#getting-started","developer_guide/contributing.html#using-the-makefile","developer_guide/contributing.html#codebase-organization","developer_guide/contributing.html#contribution-rules","developer_guide/contributing.html#style-guide","developer_guide/contributing.html#ai-policy","developer_guide/architecture.html#compiler-architecture-and-internals","developer_guide/architecture.html#resolc","developer_guide/architecture.html#reproducible-contract-builds","developer_guide/architecture.html#the-revive-compiler-libraries","developer_guide/architecture.html#evm-heap-memory","developer_guide/architecture.html#the-llvm-dependency","developer_guide/architecture.html#custom-optimizations","developer_guide/target.html#pvm-and-the-pallet-revive-runtime-target","developer_guide/target.html#target-cpu-configuration","developer_guide/target.html#why-pvm","developer_guide/target.html#host-environment-pallet-revive","developer_guide/testing.html#testing-strategy","developer_guide/testing.html#bug-compatibility-with-ethereum-solidity","developer_guide/testing.html#differential-integration-tests","developer_guide/testing.html#the-differential-testing-utility","developer_guide/cross_compilation.html#cross-compilation","developer_guide/cross_compilation.html#wasm-via-emscripten","developer_guide/cross_compilation.html#musl-libc","faq.html#faq","faq.html#what-evm-version-do-you-support","faq.html#is-inline-assembly-supported","faq.html#do-you-support-opcode-xy","faq.html#in-what-solidity-version-should-i-write-my-dapp","faq.html#tool-xy-says-the-contract-size-is-larger-than-24kb-and-will-fail-to-deploy","faq.html#is-resolc-a-drop-in-replacement-for-solc","roadmap.html#vision-and-roadmap","roadmap.html#roadmap"],"index":{"documentStore":{"docInfo":{"0":{"body":74,"breadcrumbs":2,"title":1},"1":{"body":22,"breadcrumbs":3,"title":2},"10":{"body":6,"breadcrumbs":7,"title":3},"11":{"body":33,"breadcrumbs":8,"title":2},"12":{"body":53,"breadcrumbs":9,"title":3},"13":{"body":62,"breadcrumbs":8,"title":2},"14":{"body":75,"breadcrumbs":8,"title":2},"15":{"body":10,"breadcrumbs":7,"title":1},"16":{"body":26,"breadcrumbs":8,"title":2},"17":{"body":15,"breadcrumbs":8,"title":2},"18":{"body":236,"breadcrumbs":9,"title":3},"19":{"body":31,"breadcrumbs":9,"title":3},"2":{"body":7,"breadcrumbs":4,"title":3},"20":{"body":9,"breadcrumbs":7,"title":2},"21":{"body":14,"breadcrumbs":7,"title":2},"22":{"body":11,"breadcrumbs":7,"title":2},"23":{"body":14,"breadcrumbs":7,"title":2},"24":{"body":14,"breadcrumbs":9,"title":3},"25":{"body":6,"breadcrumbs":8,"title":2},"26":{"body":9,"breadcrumbs":7,"title":1},"27":{"body":31,"breadcrumbs":8,"title":2},"28":{"body":8,"breadcrumbs":8,"title":2},"29":{"body":10,"breadcrumbs":7,"title":1},"3":{"body":15,"breadcrumbs":1,"title":0},"30":{"body":13,"breadcrumbs":7,"title":1},"31":{"body":23,"breadcrumbs":7,"title":2},"32":{"body":41,"breadcrumbs":10,"title":5},"33":{"body":6,"breadcrumbs":6,"title":1},"34":{"body":18,"breadcrumbs":8,"title":3},"35":{"body":5,"breadcrumbs":6,"title":1},"36":{"body":58,"breadcrumbs":7,"title":2},"37":{"body":64,"breadcrumbs":12,"title":7},"38":{"body":16,"breadcrumbs":7,"title":2},"39":{"body":3,"breadcrumbs":6,"title":1},"4":{"body":43,"breadcrumbs":6,"title":3},"40":{"body":101,"breadcrumbs":7,"title":2},"41":{"body":3,"breadcrumbs":6,"title":1},"42":{"body":7,"breadcrumbs":6,"title":1},"43":{"body":8,"breadcrumbs":7,"title":2},"44":{"body":4,"breadcrumbs":7,"title":2},"45":{"body":10,"breadcrumbs":7,"title":2},"46":{"body":20,"breadcrumbs":7,"title":2},"47":{"body":24,"breadcrumbs":11,"title":6},"48":{"body":57,"breadcrumbs":11,"title":6},"49":{"body":167,"breadcrumbs":9,"title":3},"5":{"body":52,"breadcrumbs":7,"title":4},"50":{"body":36,"breadcrumbs":6,"title":3},"51":{"body":21,"breadcrumbs":5,"title":2},"52":{"body":38,"breadcrumbs":5,"title":2},"53":{"body":15,"breadcrumbs":6,"title":3},"54":{"body":120,"breadcrumbs":4,"title":1},"55":{"body":11,"breadcrumbs":4,"title":2},"56":{"body":11,"breadcrumbs":6,"title":2},"57":{"body":8,"breadcrumbs":6,"title":2},"58":{"body":39,"breadcrumbs":6,"title":2},"59":{"body":85,"breadcrumbs":6,"title":2},"6":{"body":24,"breadcrumbs":5,"title":1},"60":{"body":44,"breadcrumbs":6,"title":2},"61":{"body":107,"breadcrumbs":6,"title":2},"62":{"body":112,"breadcrumbs":6,"title":2},"63":{"body":58,"breadcrumbs":7,"title":3},"64":{"body":55,"breadcrumbs":5,"title":1},"65":{"body":76,"breadcrumbs":7,"title":3},"66":{"body":65,"breadcrumbs":7,"title":3},"67":{"body":57,"breadcrumbs":7,"title":3},"68":{"body":69,"breadcrumbs":6,"title":2},"69":{"body":54,"breadcrumbs":6,"title":2},"7":{"body":21,"breadcrumbs":7,"title":3},"70":{"body":9,"breadcrumbs":12,"title":5},"71":{"body":14,"breadcrumbs":10,"title":3},"72":{"body":199,"breadcrumbs":8,"title":1},"73":{"body":34,"breadcrumbs":11,"title":4},"74":{"body":63,"breadcrumbs":6,"title":2},"75":{"body":34,"breadcrumbs":8,"title":4},"76":{"body":187,"breadcrumbs":7,"title":3},"77":{"body":73,"breadcrumbs":7,"title":3},"78":{"body":19,"breadcrumbs":6,"title":2},"79":{"body":69,"breadcrumbs":7,"title":3},"8":{"body":13,"breadcrumbs":7,"title":3},"80":{"body":12,"breadcrumbs":6,"title":2},"81":{"body":0,"breadcrumbs":2,"title":1},"82":{"body":12,"breadcrumbs":4,"title":3},"83":{"body":10,"breadcrumbs":4,"title":3},"84":{"body":4,"breadcrumbs":4,"title":3},"85":{"body":25,"breadcrumbs":5,"title":4},"86":{"body":13,"breadcrumbs":9,"title":8},"87":{"body":9,"breadcrumbs":5,"title":4},"88":{"body":66,"breadcrumbs":4,"title":2},"89":{"body":49,"breadcrumbs":3,"title":1},"9":{"body":5,"breadcrumbs":7,"title":3}},"docs":{"0":{"body":"Hello and a warm welcome to the revive Solidity compiler book! Warning Solidity on PVM is running on the pallet-revive runtime. This introduces observable semantic differences in comparison with the EVM. Study the differences section carefully. Ignoring these differences may lead to defunct contracts. Notable examples: The 63/64 gas rule isn’t implemented in the pallet (introduces potential DoS vector when calling other contracts) Contract instantiation works differently (by hash instead of by code) The gas model implemented by pallet-revive differs from Ethereum The heap size is fixed instead of gas-metered and there’s a fixed amount of stack size (contracts working fine on EVM may trap on PVM)","breadcrumbs":"Welcome » Welcome","id":"0","title":"Welcome"},"1":{"body":"Solidity dApp developers should read the user guide. Solidity on PolkaVM introduces important differences to EVM which should be well understood. Contributors will find the developer guide helpful for getting up to speed.","breadcrumbs":"Welcome » Target audience","id":"1","title":"Target audience"},"10":{"body":"Please follow the build instructions in the revive README.md.","breadcrumbs":"resolc user guide » Installation » Buidling resolc from source","id":"10","title":"Buidling resolc from source"},"11":{"body":"We aim to keep the resolc CLI usage close to solc. There are a few things and options worthwhile to know about in resolc which do not exist in the Ethereum world. This chapter explains those in more detail than the CLI help message. Tip For the complete help about CLI options, please see resolc --help.","breadcrumbs":"resolc user guide » Command Line Interface » CLI usage","id":"11","title":"CLI usage"},"12":{"body":"-O, --optimization resolc exposes the optimization level setting for the LLVM backend. The performance and size of compiled contracts varies wiedly between different optimization levels. Valid levels are the following: 0: No optimizations are applied. 1: Basic optimizations for execution time. 2: Advanced optimizations for execution time. 3: Aggressive optimizations for execution time. s: Optimize for code size. z: Aggressively optimize for code size. By default, -Oz is applied.","breadcrumbs":"resolc user guide » Command Line Interface » LLVM optimization levels","id":"12","title":"LLVM optimization levels"},"13":{"body":"--stack-size PVM is a register machine with a traditional stack memory space for local variables. This controls the total amount of stack space the contract can use. You are incentivized to keep this value as small as possible: Increasing the stack size will increase gas costs due to increased startup costs. The stack size contributes to the total memory size a contract can use, which includes the contract’s code size. Default value: 131072 Warning If the contract uses more stack memory than configured, it will compile fine but eventually revert execution at runtime!","breadcrumbs":"resolc user guide » Command Line Interface » Stack size","id":"13","title":"Stack size"},"14":{"body":"--heap-size Unlike the EVM, due to the lack of dynamic memory metering, PVM contracts emulate the EVM heap memory with a static buffer. Consequentially, instead of infinite memory with exponentially growing gas costs, PVM contracts have a finite amount of memory with constant gas costs available. You are incentivized to keep this value as small as possible:\\n1.Increasing the heap size will increase startup costs.\\n2.The heap size contributes to the total memory size a contract can use, which includes the contract’s code size Default value: 131072 Warning If the contract uses more heap memory than configured, it will compile fine but eventually revert execution at runtime!","breadcrumbs":"resolc user guide » Command Line Interface » Heap size","id":"14","title":"Heap size"},"15":{"body":"--solc Specify the path to the solc executable. By default, the one in ${PATH} is used.","breadcrumbs":"resolc user guide » Command Line Interface » solc","id":"15","title":"solc"},"16":{"body":"--debug-output-dir Dump all intermediary compiler artifacts to files in the specified directory. This includes the YUL IR, optimized and unoptimized LLVM IR, the ELF object and the PVM assembly. Useful for debugging and development purposes.","breadcrumbs":"resolc user guide » Command Line Interface » Debug artifacts","id":"16","title":"Debug artifacts"},"17":{"body":"-g Generate source based debug information in the output code file. Useful for debugging and development purposes and disabled by default.","breadcrumbs":"resolc user guide » Command Line Interface » Debug info","id":"17","title":"Debug info"},"18":{"body":"--link [--libraries ] In Solidity, 3 things can happen with libraries: They are not externally callable and thus can be inlined. The solc Solidity optimizer inlines those (usually the case). Note: resolc always activates the solc Solidity optimizer. If the solc Solidity optimizer is disabled or for some reason fails to inline them (both rare), they are not inlined and require linking. They are externally callable but still linked at compile time. This is the case if at compile time the library address is known (i.e. --libraries supplied in CLI or the corresponding setting in STD JSON input). They are linked at deploy time. This happens when the compiler does not know the library address (i.e. --libraries flag is missing or the provided libraries are incomplete, same for STD JSON input). This case is rare because it’s discourage and should never be used by production dApps. In cases 1.2 and 3: Some of the produced code blobs will be in the “unlinked” raw ELF object format and not yet deployable. To make them deployable, they need to be “linked” (done using the resolc --link linker mode explained below). The compiler emitted DELEGATECALL instructions to call non-inlined (unlinked) libraries. The contract deployer must make sure to deploy any libraries prior to contract deployment. Warning Using deploy time linking is officially discouraged. Mainly due to bytecode hashes changing after the fact. We decided to support it in resolc regardless, due to popular request. Similar to how it works in solc, --libraries may be used to provide libraries during linking mode. Unlike with solc, where linking implies a simple string substitution mechanism, resolc needs to resolve actual missing ELF symbols. This is due to how factory dependencies work in PVM. As a consequence, it isn’t sufficient to just provide the unlinked blobs to the linker. Instead, they must be provided in the exact same directory structure the Solidity source code was found during compile time. Example: The contract src/foo/bar.sol:Bar is involved in deploy time linking. It may be a factory dependency. The contract blob needs to be provided inside a relative src/foo/ directory to --link. Otherwise symbol resolution may fail. Note Tooling is supposed to take care of this. In the future, we may append explicit linkage data to simplify the deploy time linking feature.","breadcrumbs":"resolc user guide » Command Line Interface » Deploy time linking","id":"18","title":"Deploy time linking"},"19":{"body":"The resolc compiler driver is published as an NPM package under @parity/resolc. It’s usable from Node.js code or directly from the command line: npx @parity/resolc@latest --bin crates/integration/contracts/flipper.sol -o /tmp/out Note While the npm package makes a nice portable option, it doesn’t expose all options.","breadcrumbs":"resolc user guide » JS NPM package » JS NPM package","id":"19","title":"JS NPM package"},"2":{"body":"Head to contracts.polkadot.io for more general information about contracts on Polkadot.","breadcrumbs":"Welcome » Other Polkadot contracts resources","id":"2","title":"Other Polkadot contracts resources"},"20":{"body":"resolc achieved successful integration with a variety of third party developer tools.","breadcrumbs":"resolc user guide » Tooling integration » Tooling integration","id":"20","title":"Tooling integration"},"21":{"body":"Support for resolc is available in forks of the hardhat and foundry Solidity toolkits: The Parity Hardhat fork The Parity Foundry fork","breadcrumbs":"resolc user guide » Tooling integration » Solidity toolkits","id":"21","title":"Solidity toolkits"},"22":{"body":"resolc is available on godbolt.org for the Solidity and Yul input languages. See also the announcement post on the forum.","breadcrumbs":"resolc user guide » Tooling integration » Compiler explorer","id":"22","title":"Compiler explorer"},"23":{"body":"There is remix IDE fork with resolc support at remix.polkadot.io. Unfortunately this is no longer actively maintained (there might be bugs and outdated resolc versions).","breadcrumbs":"resolc user guide » Tooling integration » Remix IDE","id":"23","title":"Remix IDE"},"24":{"body":"The revive compiler is mostly compatible with the solc standard JSON interface. There are a few additional (PVM related) input configurations:","breadcrumbs":"resolc user guide » Standard JSON interface » Standard JSON interface","id":"24","title":"Standard JSON interface"},"25":{"body":"Used to configure PVM specific compiler settings.","breadcrumbs":"resolc user guide » Standard JSON interface » The settings.polkavm object","id":"25","title":"The settings.polkavm object"},"26":{"body":"A boolean value allowing to enable debug information. Corresponds to resolc -g.","breadcrumbs":"resolc user guide » Standard JSON interface » settings.polkavm.debugInformation","id":"26","title":"settings.polkavm.debugInformation"},"27":{"body":"Used to apply PVM specific memory configuration settings. settings.polkavm.memoryConifg.heapSize A numerical value allowing to configure the contract heap size. Corresponds to resolc --heap-size. settings.polkavm.memoryConifg.stackSize A numerical value allowing to configure the contract stack size. Corresponds to resolc --stack-size.","breadcrumbs":"resolc user guide » Standard JSON interface » The settings.polkavm.memoryConfig object","id":"27","title":"The settings.polkavm.memoryConfig object"},"28":{"body":"The settings.optimizer object is augmented with support for PVM specific optimization settings.","breadcrumbs":"resolc user guide » Standard JSON interface » The settings.optimizer object","id":"28","title":"The settings.optimizer object"},"29":{"body":"A single char value to configure the LLVM optimizer settings. Corresponds to resolc -O.","breadcrumbs":"resolc user guide » Standard JSON interface » settings.optimizer.mode","id":"29","title":"settings.optimizer.mode"},"3":{"body":"This mdBook documents the revive Solidity compiler project. The content is found under book/. Run make book to observe changes.","breadcrumbs":"Welcome » About","id":"3","title":"About"},"30":{"body":"Allows to specify arbitrary command line arguments to LLVM initialization. Used mainly for development and debugging purposes.","breadcrumbs":"resolc user guide » Standard JSON interface » settings.llvmArguments","id":"30","title":"settings.llvmArguments"},"31":{"body":"This section highlights some potentially observable differences in the YUL EVM dialect translation compared to Ethereum Solidity. Solidity developers deploying dApps to pallet-revive ought to read and understand this section well.","breadcrumbs":"resolc user guide » Differences to EVM » Differences to EVM","id":"31","title":"Differences to EVM"},"32":{"body":"Our contract runtime does not differentiate between runtime code and deploy (constructor) code.\\nInstead, both are emitted into a single PVM contract code blob and live on-chain.\\nTherefore, in EVM terminology, the deploy code equals the runtime code. Tip In constructor code, the codesize instruction will return the call data size instead of the actual code blob size.","breadcrumbs":"resolc user guide » Differences to EVM » Deploy code vs. runtime code","id":"32","title":"Deploy code vs. runtime code"},"33":{"body":"We are aware of the following differences in the translation of Solidity code.","breadcrumbs":"resolc user guide » Differences to EVM » Solidity","id":"33","title":"Solidity"},"34":{"body":"pallet-revive doesn’t apply the 63/64 gas rule. We strongly advice to change any code calling untrusted contracts to supply a limited amount of gas only!","breadcrumbs":"resolc user guide » Differences to EVM » The 63/64 gas rule","id":"34","title":"The 63/64 gas rule"},"35":{"body":"This returns the bytecode keccak256 hash instead.","breadcrumbs":"resolc user guide » Differences to EVM » address.creationCode","id":"35","title":"address.creationCode"},"36":{"body":"The below list contains noteworthy differences in the translation of YUL functions. Note Many functions receive memory buffer offset pointer or size arguments. The PVM pointer size is 32 bit, supplying memory offset or buffer size values above 2^32-1 may lead to OutOfGas errors trap contract execution. The solc compiler ought to always emit valid memory references, so Solidity dApp authors don’t need to worry about this unless they deal with low level assembly code.","breadcrumbs":"resolc user guide » Differences to EVM » YUL functions","id":"36","title":"YUL functions"},"37":{"body":"In general, revive preserves the memory layout, meaning low level memory operations are supported. However, a few caveats apply: The EVM linear heap memory is emulated using a fixed byte buffer of 128kb. This implies that the maximum memory a contract can use is limited to 128kb (on Ethereum, contract memory is capped by gas and therefore varies). Thus, accessing memory offsets larger than the fixed buffer size will trap the contract at runtime with an OutOfBound error. The compiler might detect and optimize unused memory reads and writes, leading to a different msize compared to what the EVM would see.","breadcrumbs":"resolc user guide » Differences to EVM » mload, mstore, msize, mcopy (memory related functions)","id":"37","title":"mload, mstore, msize, mcopy (memory related functions)"},"38":{"body":"In the constructor code, the offset is ignored and this always returns 0. Warning pallet-revive restricts the calldata size (to 128kb at the time of writing).","breadcrumbs":"resolc user guide » Differences to EVM » calldataload, calldatacopy","id":"38","title":"calldataload, calldatacopy"},"39":{"body":"Only supported in constructor code.","breadcrumbs":"resolc user guide » Differences to EVM » codecopy","id":"39","title":"codecopy"},"4":{"body":"resolc is a Solidity v0.8 compiler for Polkadot native smart contracts. Solidity compiled with resolc targets PolaVM (PVM). Thanks to additional compiler optimizations and the PVM JIT, contract code can execute much faster than the EVM equivalent. resolc supports almost all Solidity v0.8 features including inline assembly, offering a high level of comptability with the Ethereum Solidity reference implementation.","breadcrumbs":"resolc user guide » resolc user guide","id":"4","title":"resolc user guide"},"40":{"body":"Deployments on revive work different than on EVM. In a nutshell: Instead of supplying the deploy code concatenated with the constructor arguments (the EVM deploy model), the revive runtime expects two pointers: A buffer containing the code hash to deploy. The constructor arguments buffer. To make contract instantiation using the new keyword in Solidity work seamlessly, revive translates the dataoffset and datasize instructions so that they assume the contract hash instead of the contract code.\\nThe hash is always of constant size.\\nThus, revive is able to supply the expected code hash and constructor arguments pointer to the runtime. Warning This might fall apart in code creating contracts inside assembly blocks. We strongly discourage using the create family opcodes to manually craft deployments in assembly blocks! Usually, the reason for using assembly blocks is to save gas, which is likely futile on revive due to the underlying differences in the VM architectures, gas models and transaction costs.","breadcrumbs":"resolc user guide » Differences to EVM » create, create2","id":"40","title":"create, create2"},"41":{"body":"Returns the contract hash.","breadcrumbs":"resolc user guide » Differences to EVM » dataoffset","id":"41","title":"dataoffset"},"42":{"body":"Returns the contract hash size (constant value of 32).","breadcrumbs":"resolc user guide » Differences to EVM » datasize","id":"42","title":"datasize"},"43":{"body":"pallet-revive restricts the returndata size (to 128kb at the time of writing).","breadcrumbs":"resolc user guide » Differences to EVM » revert, return","id":"43","title":"revert, return"},"44":{"body":"Translates to a constant value of 2500000000000000.","breadcrumbs":"resolc user guide » Differences to EVM » prevrandao, difficulty","id":"44","title":"prevrandao, difficulty"},"45":{"body":"Only valid to use in EVM (they also have no use case in PVM) and produce a compile time error.","breadcrumbs":"resolc user guide » Differences to EVM » pc, extcodecopy","id":"45","title":"pc, extcodecopy"},"46":{"body":"Related to the Ethereum rollup model and produce a compile time error. Polkadot offers a superior rollup model, removing the use case for blob data related opcodes.","breadcrumbs":"resolc user guide » Differences to EVM » blobhash, blobbasefee","id":"46","title":"blobhash, blobbasefee"},"47":{"body":"There are two different compilation pipelines available in solc and there are small differences between them. Since resolc processes the YUL IR, always assume the solc IR based codegen behavior for contracts compiled with the revive compiler.","breadcrumbs":"resolc user guide » Differences to EVM » Difference regarding the solc via-ir mode","id":"47","title":"Difference regarding the solc via-ir mode"},"48":{"body":"With via-ir, base constructors run before derived state variables are initialized: contract InnerContract { uint public innerConstructedStartTokenId; constructor() { innerConstructedStartTokenId = _startTokenId(); } function _startTokenId() internal view virtual returns (uint) { return 0; }\\n} contract Test is InnerContract { uint public START_TOKEN_ID = 1; constructor() InnerContract() { } function _startTokenId() internal view virtual override returns (uint) { return START_TOKEN_ID; }\\n} Here, innerConstructedStartTokenId in Test returns 0 (with legacy EVM codegen it’d return 1).","breadcrumbs":"resolc user guide » Differences to EVM » Example: State variable initialization order in inheritance","id":"48","title":"Example: State variable initialization order in inheritance"},"49":{"body":"Note This is not yet implemented but something for consideration on the roadmap. Solidity - tightly coupled to the EVM - introduces some inherent inefficiencies that are by design and either needs to be followed or can’t be easily worked around, even with efforts like better optimized compiler and VM implementations. This represents a technical dead end. So far the EVM sees no adoption beyond the blockchain industry. Chances are that the EVM end up deprecated for technical reasons (or maybe not and the RISC-V idea gets abandoned, who knows). PVM, however, is a general purpose VM. It supports LLVM based mainstream programming languages like Rust. It’s a common software engineering practice to compose applications from pieces written in multiple languages, using each to their own strength. For example, AI solutions traditionally use the python scripting language for convenient developer experience, while the underlying AI models get implemented in a lower level language such as C++. The same pattern can of course be applied to dApps, where we’d expect application specific languages like Solidity mixed with libraries implementing computationally complex algorithms in a lower level language. Business logic and user interfaces are naturally implemented as regular Solidity dApps which can include (link against) Rust libraries. Rust is a fast, safe low level language and the Polkadot SDK is written in Rust itself, making it an excellent choice. For example, ZK proof verifiers or expensive DeFi primitives would benefit greatly from Rust implementations. revive provides tooling support and a small Rust contracts SDK for seamless integration with Rust libraries.","breadcrumbs":"resolc user guide » Rust contract libraries » Rust contract libraries","id":"49","title":"Rust contract libraries"},"5":{"body":"revive is the name of the overarching “Solidity to PolkaVM” compiler project, which contains multiple components (for example the Yul parser, the code generation library, the resolc executable itself, and many more things). resolc is the name of the compiler driver executable, combining many revive components in a single and easy to use binary application. In other words, revive is the whole compiler infrastructure (more like LLVM) and resolc is a user-facing single-entrypoint compiler frontend (more like clang).","breadcrumbs":"resolc user guide » revive vs. resolc nomenclature","id":"5","title":"revive vs. resolc nomenclature"},"50":{"body":"Running contract code usually requires a blockchain node. While local dev nodes can be used, sometimes it’s just not desirable to do so. Instead, it can be much more convenient to run and debug contract code with a stripped down environment. This is where the revive-runner comes in handy. In a nutshell, it is a single-binary no-blockchain pallet-revive runtime.","breadcrumbs":"revive-runner sandbox » revive-runner sandbox","id":"50","title":"revive-runner sandbox"},"51":{"body":"Inside the root revive repository directory, install it from source (requires Rust installed): make install-revive-runner After installing, see revive-runner --help for usage help.","breadcrumbs":"revive-runner sandbox » Installation and usage","id":"51","title":"Installation and usage"},"52":{"body":"The standard RUST_LOG environment variable controls the log output from the contract execution. This includes revive runtime logs and PVM execution trace logs. Sometimes it’s convenient to have more fine granular insight. Some useful filters: RUST_LOG=runtime=trace: The pallet-revive runtime trace logs. RUST_LOG=polkavm=trace: Low level PolkaVM instruction tracing.","breadcrumbs":"revive-runner sandbox » Trace logs","id":"52","title":"Trace logs"},"53":{"body":"To avoid running the constract in an unitialized state, revive-runner automatically instantiates the contract before calling it (constructor arguments can be provided).","breadcrumbs":"revive-runner sandbox » Automatic contract instantiation","id":"53","title":"Automatic contract instantiation"},"54":{"body":"Suppose we want to trace the syscalls of the execution of a compiled contract file Flipper.pvm: RUST_LOG=runtime=trace revive-runner -f Flipper.pvm\\n[DEBUG runtime::revive] Contract memory usage: purgable=6144/3145728 KB baseline=103063/1572864\\n[TRACE runtime::revive::strace] call_data_size() = Ok(0) gas_consumed: Weight { ref_time: 985209, proof_size: 0 }\\n[TRACE runtime::revive::strace] value_transferred(out_ptr: 4294836096) = Ok(()) gas_consumed: Weight { ref_time: 2937634, proof_size: 0 }\\n[TRACE runtime::revive::strace] call_data_copy(out_ptr: 131216, out_len: 0, offset: 0) = Ok(()) gas_consumed: Weight { ref_time: 4084483, proof_size: 0 }\\n[TRACE runtime::revive::strace] seal_return(flags: 0, data_ptr: 131216, data_len: 0) = Err(TrapReason::Return(ReturnData { flags: 0, data: [] })) gas_consumed: Weight { ref_time: 5510615, proof_size: 0 }\\n[TRACE runtime::revive] frame finished with: Ok(ExecReturnValue { flags: (empty), data: [] })\\n[TRACE runtime::revive::strace] call_data_size() = Ok(0) gas_consumed: Weight { ref_time: 985209, proof_size: 0 }\\n[TRACE runtime::revive::strace] seal_return(flags: 1, data_ptr: 131088, data_len: 0) = Err(TrapReason::Return(ReturnData { flags: 1, data: [] })) gas_consumed: Weight { ref_time: 2456669, proof_size: 0 }\\n[TRACE runtime::revive] frame finished with: Ok(ExecReturnValue { flags: REVERT, data: [] })","breadcrumbs":"revive-runner sandbox » Example","id":"54","title":"Example"},"55":{"body":"This chapter covers internal aspects of the compiler and helps contributors getting started with the revive codebase.","breadcrumbs":"Developer Guide » Developer guide","id":"55","title":"Developer guide"},"56":{"body":"The revive compiler is an open source software project and we gladly accept quality contributions from anyone!","breadcrumbs":"Developer Guide » Contributor guide » Contributor guide","id":"56","title":"Contributor guide"},"57":{"body":"A quick reference on how to build the Solidity compiler is maintained in the project’s README.md.","breadcrumbs":"Developer Guide » Contributor guide » Getting started","id":"57","title":"Getting started"},"58":{"body":"The Makefile comprehensively encapsulates all development aspects of this codebase. It is kept concise and readable. Please read and use it! You’ll learn for example: How to build and install a resolc development version. How to run tests and benchmarks. How to cross-compile resolc. As a general rule-of-thumb: If make test runs fine locally, chances for green CI pipelines are good.","breadcrumbs":"Developer Guide » Contributor guide » Using the Makefile","id":"58","title":"Using the Makefile"},"59":{"body":"For the most parts, revive is a rather standard Rust workspace codebase. There are some non-Rust dependencies, which sometimes complicates things a little bit. The crates/ dir All Rust crates live under the crates/ directory. The workspace automatically considers any crate found therein. If you need to add a new create, please implement it there. Compiler library crates should be named with the revive- prefix. The crate location doesn’t need the prefix. Dependencies Dependencies should be added as workspace dependencies. Try to avoid pinning dependencies whenever possible. If possible, add dev dependencies as dev-dependencies only. Please do always include the Cargo.lock dependency lock file with your PR. Please don’t run cargo update together with other changes (it is preferred to update the lock file in a dedicated dependency update PR).","breadcrumbs":"Developer Guide » Contributor guide » Codebase organization","id":"59","title":"Codebase organization"},"6":{"body":"Building Solidity contracts for PolkaVM requires installing the following two compilers: solc: The Ethereum Solidity reference compiler implementation. resolc: The revive Solidity compiler YUL frontend and PolkaVM code generator.","breadcrumbs":"resolc user guide » Installation » Installation","id":"6","title":"Installation"},"60":{"body":"Changes must be submitted via a pull request (PR) to the github upstream repository. Ensure that your branch passes make test locally when submitting a pull request. A PR must not be merged until CI fully passes. Exceptions can be made (for example to fix CI issues itself). No force pushes to the main branch and open PR branches. Maintainers can request changes or deny contributions at their own discretion.","breadcrumbs":"Developer Guide » Contributor guide » Contribution rules","id":"60","title":"Contribution rules"},"61":{"body":"We require the official Rust formatter and clippy linter. In addition to that, please also consider the following best-effort aspects: Avoid magic numbers and strings. Instead, add them as module constants. Avoid abbreviated variable and function names. Always provide meaningful and readable symbols. Don’t write macros and don’t use third party macros for things that can easily be expressed in few lines of code or outlined into functions. Avoid import aliasing. Please use the parent or fully qualified path for conflicting symbols. Any inline comments must provide additional semantic meaning, explain counter-intuitive behavior or highlight non-obvious design decisions. In other words, try to make the code expressive enough to a degree it doesn’t need comments expressing the same thing again in the English language. Delete such comments if your AI assistant generated them. Public items must have a meaningful doc comment. Provide meaningful panic messages to .expect() or just use .unwrap().","breadcrumbs":"Developer Guide » Contributor guide » Style guide","id":"61","title":"Style guide"},"62":{"body":"Contributors may use whatever AI assistance tools they wish to whatever degree they wish in the process of creating their contribution, given they acknowledge the following: Project maintainers may reject any contribution (or portions of it) if the contribution shows signs of problematic involvement of generative AI. Judgement of “problematic involvement” lies at the sole discretion of project maintainers. No proof (whether a contribution was in fact AI generated or not) is required. Rationale: No one enjoys reading soulless and uncanny LLM slop. Please review and fix any AI slop yourself prior to submitting a PR. A Solidity compiler is security sensitive software. Even miniscule mistakes can ultimately lead to loss of funds. AI models are inherently stochastic. They regurarly fail to capture important nuances or produce straight hallucinations. Code that was “blindly” generated has no home here. revive is a large codebase. Generative AI assistants may not have enough “context window” to sufficiently capture correctness, consistency and style aspects of the codebase. We’d like to keep this codebase maintainable by humans for the forseeable future.","breadcrumbs":"Developer Guide » Contributor guide » AI policy","id":"62","title":"AI policy"},"63":{"body":"revive relies on solc, the Ethereum Solidity compiler, as the Solidity frontend to process smart contracts written in Solidity. LLVM, a popular and powerful compiler framework, is used as the compiler backend and does the heavy lifting in terms of optimizitations and RISC-V code generation. revive mainly takes care of lowering the Yul intermediate representation (IR) produced by solc to LLVM IR. This approach provides a good balance between maintaining a high level of Ethereum compatibility, good contract performance and feasible engineering efforts.","breadcrumbs":"Developer Guide » Compiler architecture » Compiler architecture and internals","id":"63","title":"Compiler architecture and internals"},"64":{"body":"resolc is the overarching compiler driver library and binary. When compiling a Solidity source file with resolc, the following steps happen under the hood: solc is used to lower the Solidity source code into YUL intermediate representation. revive lowers the YUL IR into LLVM IR. LLVM optimizes the code and emits a RISC-V ELF shared object (through LLD). The PolkaVM linker finally links the ELF shared object into a PolkaVM blob. This compilation process can be visualized as follows:","breadcrumbs":"Developer Guide » Compiler architecture » resolc","id":"64","title":"resolc"},"65":{"body":"Because on-chain contract code is identified via its code blob hash, it is crucial to maintain reproducible contract builds. A given compiler version must reproduce the contract build exactly on every target platform resolc supports via the official binary releases. To ensure this, we employ the following measures: The code generation must be fully deterministic. For example iterating over standard HashMap invalidates this due to its internal state, making it an invalid operation in revive. To circumvent that, a BTreeMap can be used instead. We release fully statically linked resolc binaries. This prevents dynamic linking of potentially differentiating libraries. The only non-bundled dependency is the solc compiler. This is considered fine because the same properties apply to solc.","breadcrumbs":"Developer Guide » Compiler architecture » Reproducible contract builds","id":"65","title":"Reproducible contract builds"},"66":{"body":"The main compiler logic is implemented in the revive-yul and revive-llvm-context crates. The Yul library implements a lexer and parser and lowers the resulting tree into LLVM IR. It does so by emitting LL using the LLVM builder and our own revive-llvm-context compiler context crate. The revive LLVM context crate encapsulates code generation logic (decoupled from the parser). The Yul library also implements a simple visitor interface (see visitor.rs). If you want to work with the AST, it is strongly recommended to implement visitors. The LLVM code generation is implemented using a dedicated trait for historical reasons only.","breadcrumbs":"Developer Guide » Compiler architecture » The revive compiler libraries","id":"66","title":"The revive compiler libraries"},"67":{"body":"PVM doesn’t offer a similar API. Hence the emitted contract code emulates the linear EVM heap memory using a static byte buffer. Data inside this byte buffer is kept big endian for EVM compatibility reasons (unaligned access is allowed and makes optimizing this non-trivial). Unlike with the EVM, where heap memory usage is gas metered, our heap size is static (the size is user controllable via a setting flag). The compiler emits bound checks to prevent overflows.","breadcrumbs":"Developer Guide » Compiler architecture » EVM heap memory","id":"67","title":"EVM heap memory"},"68":{"body":"LLVM is a special non Rust dependency. We interface its builder interface via the inkwell wrapper crate. We use upstream LLVM, but release and use our custom builds. We require the compiler builtins specifically built for the PVM rv64emacb target and always leave assertions on. Furthermore, we need cross builds because resolc itself targets emscripten and musl. The revive-llvm-builer functions as a cross-platform build script and is used to build and release the LLVM dependency. We also maintain the lld-sys crate for interfacing with LLD. The LLVM linker is used during the compilation process, but we don’t want to distribute another binary.","breadcrumbs":"Developer Guide » Compiler architecture » The LLVM dependency","id":"68","title":"The LLVM dependency"},"69":{"body":"At the moment, no significant custom optimizations are implemented. Thus, we are missing some optimization opportunities that neither solc nor LLVM can realize (due to their lack of domain specific knowledge about the semantics of our target environment). Furthermore, solc optimizes for EVM gas and a target machine orthogonal to our target (BE 256-bit stack machine EVM vs. 64-bit LE RISC architecture PVM). We have started working on an additional IR layer between Yul and LLVM to capture missed optimization opportunities, though.","breadcrumbs":"Developer Guide » Compiler architecture » Custom optimizations","id":"69","title":"Custom optimizations"},"7":{"body":"resolc is supported an all major operating systems and installation is straightforward.\\nPlease find our binary releases for the following platforms: Linux (MUSL) MacOS (universal) Windows Wasm via emscripten","breadcrumbs":"resolc user guide » Installation » resolc binary releases","id":"7","title":"resolc binary releases"},"70":{"body":"The revive compiler targets PolkaVM (PVM) via pallet-revive on Polkadot.","breadcrumbs":"Developer Guide » PVM and the pallet-revive runtime target » PVM and the pallet-revive runtime target","id":"70","title":"PVM and the pallet-revive runtime target"},"71":{"body":"The exact target CPU configuration can be found here. Note The PVM linker requires fully relocatable ELF objects.","breadcrumbs":"Developer Guide » PVM and the pallet-revive runtime target » Target CPU configuration","id":"71","title":"Target CPU configuration"},"72":{"body":"PVM is a RISC-V based VM designed to overcome the flaws of WebAssebmly (Wasm). Wasm was believed to be a more efficient successor to the rather slow EVM. However, Wasm is far from an ideal target for smart contracts as some of its design decisions are unfavorable for short-lived workloads. The main problem is on-chain Wasm bytecode compilation or interpretation overhead. Prior benchmarks consistently ignoring this overhead seeded the blockchain industry with flawed assumptions: Only when ignoring the startup overhead Wasm is much faster than the slow computing EVM. In practice however, gains are nullified entirely and Wasm loses completely even against very slow VMs like the EVM. Executing Wasm contracts is in fact so inefficient that typical contract workloads are orders of magnitude more expensive than the equivalent EVM variant. On the other hand, since RISC-V is similar to CPUs found in validator hardware (x86 and ARM), bytecode translation mostly boils down to a linear mapping from one instruction to another. The embedded ISA specification reduces the number of general purpose registers, in turn removing the need for expensive register allocation. This guarantees single-pass O(n) JIT compilation of contract bytecode. The close proximity of PVM bytecode with actual validator CPU bytecode effectively allows to move all expensive compilation workload off-chain. Benchmarks ( 1, 2) show that with the PVM JIT, sandboxed PVM code executes at around half the speed of native code, which falls into the same ballpark of the state-of-the-art wasmtime Wasm implementation (while EVM sits somewhere around 1/10 to less than 1/100 of native speed). However, the PVM JIT compiler only uses a fraction of the time wasmtime requires to compile the code. Note The PVM JIT isn’t available yet in pallet-revive. At the time of writing, the contract code is interpreted, which is orders of magnitude slower than the JIT.","breadcrumbs":"Developer Guide » PVM and the pallet-revive runtime target » Why PVM","id":"72","title":"Why PVM"},"73":{"body":"The revive compiler targets the pallet-revive runtime environment. pallet-revive exposes a syscall like interface for contract interactions with the host environment. This is provided by the revive-runtime-api library. After the initial launch on the Polkadot Asset Hub blockchain, the runtime API is considered stable and backwards compatible indefinitively.","breadcrumbs":"Developer Guide » PVM and the pallet-revive runtime target » Host environment: pallet-revive","id":"73","title":"Host environment: pallet-revive"},"74":{"body":"Contributors are encouraged to implement some appropriate unit and integration tests together with any bug fixes or new feature implementations. However, when it comes to testing the code generation logic, our testing strategy goes way beyond simple unit and integration tests. This chapter explains how the revive compiler implementation is tested for correctness and how we define correctness. Tip Running the integration tests require the evm tool from go-ethereum in your $PATH. Either install it using your package manager or to build it from source: git clone https://github.com/ethereum/go-ethereum/\\ncd go-ethereum\\nmake all\\nexport PATH=/path/to/go-ethereum/build/bin/:$PATH","breadcrumbs":"Developer Guide » Testing strategy » Testing strategy","id":"74","title":"Testing strategy"},"75":{"body":"As a Solidity compiler, we aim to preserve contract code semantics as close as possible to Solidity compiled to EVM with the solc reference implementation. As highlighted in the user guide, due to the underlying target difference, this isn’t always possible. However, wherever it is possible, we follow the philosophy of bug compatibility with the Ethereum contracts stack.","breadcrumbs":"Developer Guide » Testing strategy » Bug compatibility with Ethereum Solidity","id":"75","title":"Bug compatibility with Ethereum Solidity"},"76":{"body":"A high level of bug compatibility with Ethereum is ensured through differential testing with the Ethereum solc and EVM contracts stack. The revive-integration library is the central integration test utility, providing a set of Solidity integration test cases. Further, it implements differential tests against the reference implementation by combining the revive-runner sandbox, the go-ethereum EVM tool and the revive-differential. The revive-runner library provides a declarative test specification format. This vastly simplifies writing differential test cases and removes a lot of room for errors in test logic. Example: { \\"differential\\": true, \\"actions\\": [ { \\"Instantiate\\": { \\"code\\": { \\"Solidity\\": { \\"contract\\": \\"Bitwise\\" } } } }, { \\"Call\\": { \\"dest\\": { \\"Instantiated\\": 0 }, \\"data\\": \\"3fa4f245\\" } } ]\\n} Above example instantiates the Bitwise contract and calls it with some defined calldata. The revive-runner library implements a helper wrapper to execute test specs on the go-ethereum standalone evm tool. This allows the revive-runner to execute specs against the EVM and the pallet-revive runtime. Key to differential testing is setting \\"differential\\": true, resulting in the following: The Bitwise contract is compiled to EVM and PVM code. The runner executes the defined actions on the EVM and collects all state changes (storage, balance) and execution results. The runner executes each action on the PVM. Observed state changes after each step as well as the final execution result is asserted to match the EVM counterparts exactly. Note how we never defined any expected outcome manually. Instead, we simply observe and collect the data defining the “correct” outcome. Differential testing in combination with declarative test specifications proved to be simple, yet very effective, in ensuring expected Ethereum Solidity semantics on pallet-revive.","breadcrumbs":"Developer Guide » Testing strategy » Differential integration tests","id":"76","title":"Differential integration tests"},"77":{"body":"A lot of nuanced bugs caused by tiny implementation details inside the revive compiler and the pallet-revive runtime could be identified and eliminated early on thanks to the differential testing strategy. Thus, we decided to take this approach further and created a comprehensive test runner and a large suite of more complex test cases. The Revive Differential Tests follow the exact same strategy but implement a much more powerful test spec format, spec runner and reports. This allows differentially testing much more complex test cases (for example testing Uniswap pair creations and swaps), executed via transactions sent to actual blockchain nodes.","breadcrumbs":"Developer Guide » Testing strategy » The differential testing utility","id":"77","title":"The differential testing utility"},"78":{"body":"We cross-compile the resolc.js frontend executable to Wasm for running it in a Node.js or browser environment. The musl target is used to obtain statically linked ELF binaries for Linux.","breadcrumbs":"Developer Guide » Cross compilation » Cross compilation","id":"78","title":"Cross compilation"},"79":{"body":"The REVIVE_LLVM_TARGET_PREFIX environment variable is used to control the target environment LLVM dependency. This requires a compatible LLVM build, obtainable via the revive-llvm build script. Example: # Build the host LLVM dependency with PolkaVM target support\\nmake install-llvm\\nexport LLVM_SYS_181_PREFIX=${PWD}/target-llvm/gnu/target-final # Build the target LLVM dependency with PolkaVM target support\\nrevive-llvm emsdk\\nsource emsdk/emsdk_env.sh\\nrevive-llvm --target-env emscripten build --llvm-projects lld\\nexport REVIVE_LLVM_TARGET_PREFIX=${PWD}/target-llvm/emscripten/target-final # Build the resolc frontend executable\\nmake install-wasm\\nmake test-wasm","breadcrumbs":"Developer Guide » Cross compilation » Wasm via emscripten","id":"79","title":"Wasm via emscripten"},"8":{"body":"resolc uses solc during the compilation process, please refer to the Ethereum Solidity documentation for installation instructions.","breadcrumbs":"resolc user guide » Installation » Installing the solc dependency","id":"8","title":"Installing the solc dependency"},"80":{"body":"rust-musl-cross is a straightforward way to cross compile Rust to musl. The Dockerfile is an executable example of how to do that.","breadcrumbs":"Developer Guide » Cross compilation » musl libc","id":"80","title":"musl libc"},"81":{"body":"","breadcrumbs":"FAQ » FAQ","id":"81","title":"FAQ"},"82":{"body":"We neither do nor don’t support any EVM version. We support Solidity versions, starting from solc version 0.8.0 onwards.","breadcrumbs":"FAQ » What EVM version do you support?","id":"82","title":"What EVM version do you support?"},"83":{"body":"Yes, almost all inline assembly features are supported ( see the differences in Yul translation chapter).","breadcrumbs":"FAQ » Is inline assembly supported","id":"83","title":"Is inline assembly supported"},"84":{"body":"See above, the same applies.","breadcrumbs":"FAQ » Do you support opcode XY?","id":"84","title":"Do you support opcode XY?"},"85":{"body":"We generally recommend to always use the latest supported version to profit from latest bugfixes, features and performance improvements. Find out about the latest supported version by running resolc --supported-solc-versions or checking here.","breadcrumbs":"FAQ » In what Solidity version should I write my dApp?","id":"85","title":"In what Solidity version should I write my dApp?"},"86":{"body":"The 24kb code size restriction only exist for the EVM. Our limit is currently around 1mb and may increase further in the future.","breadcrumbs":"FAQ » Tool XY says the contract size is larger than 24kb and will fail to deploy?","id":"86","title":"Tool XY says the contract size is larger than 24kb and will fail to deploy?"},"87":{"body":"No. resolc aims to work similarly to solc, but it’s not considered a drop-in replacement.","breadcrumbs":"FAQ » Is resolc a drop-in replacement for solc?","id":"87","title":"Is resolc a drop-in replacement for solc?"},"88":{"body":"The revive compiler speeds up Solidity contracts significantly. revive provides a decisive edge over other contract platforms. Notably, the compiler eliminates the need of rewriting Solidity dApps in Rust or even as single dApp parachains for scaling reasons. Retaining as high compatibility with Ethereum Solidity as possible keeps entry barriers low. We believe in Dr. Gavin Wood’s ĐApps: What Web 3.0 Looks Like manifesto and the ecosystem of the Solidity programming language. Our motivation lies in the realization that for a true web3 revolution, significant scaling efforts, like the ones provided by the PVM and this project, are necessary to unfold.","breadcrumbs":"Roadmap and Vision » Vision and Roadmap","id":"88","title":"Vision and Roadmap"},"89":{"body":"The first major release, resolc v1.0.0, emits functional PVM code from given Solidity sources. It relies on solc and LLVM for optimizations. The main priority of this release was delivering a mostly feature complete and safe Solidity v0.8.0 compiler. Focus for the second major release is on the custom optimization pipeline, which aims to significantly improve emitted code blob sizes. The below roadmap gives a rough overview of the project’s development timeline.","breadcrumbs":"Roadmap and Vision » Roadmap","id":"89","title":"Roadmap"},"9":{"body":"We distribute the revive compiler as node.js module.","breadcrumbs":"resolc user guide » Installation » revive NPM package","id":"9","title":"revive NPM package"}},"length":90,"save":true},"fields":["title","body","breadcrumbs"],"index":{"body":{"root":{"0":{".":{"8":{".":{"0":{"df":1,"docs":{"82":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":5,"docs":{"12":{"tf":1.0},"38":{"tf":1.0},"48":{"tf":1.4142135623730951},"54":{"tf":3.4641016151377544},"76":{"tf":1.0}}},"1":{".":{"2":{"df":1,"docs":{"18":{"tf":1.0}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"s":{"df":1,"docs":{"14":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"/":{"1":{"0":{"0":{"df":1,"docs":{"72":{"tf":1.0}}},"df":1,"docs":{"72":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"2":{"8":{"df":0,"docs":{},"k":{"b":{"df":3,"docs":{"37":{"tf":1.4142135623730951},"38":{"tf":1.0},"43":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}},"3":{"1":{"0":{"7":{"2":{"df":2,"docs":{"13":{"tf":1.0},"14":{"tf":1.0}}},"df":0,"docs":{}},"8":{"8":{"df":1,"docs":{"54":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"2":{"1":{"6":{"df":1,"docs":{"54":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":5,"docs":{"12":{"tf":1.0},"36":{"tf":1.0},"48":{"tf":1.4142135623730951},"54":{"tf":1.4142135623730951},"72":{"tf":1.0}},"m":{"b":{"df":1,"docs":{"86":{"tf":1.0}}},"df":0,"docs":{}}},"2":{".":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":1,"docs":{"14":{"tf":1.0}}}}}},"4":{"5":{"6":{"6":{"6":{"9":{"df":1,"docs":{"54":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{},"k":{"b":{"df":1,"docs":{"86":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"5":{"0":{"0":{"0":{"0":{"0":{"0":{"0":{"0":{"0":{"0":{"0":{"0":{"0":{"0":{"df":1,"docs":{"44":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"6":{"df":1,"docs":{"69":{"tf":1.0}}},"df":0,"docs":{}},"9":{"3":{"7":{"6":{"3":{"4":{"df":1,"docs":{"54":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"^":{"3":{"2":{"df":1,"docs":{"36":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":2,"docs":{"12":{"tf":1.0},"72":{"tf":1.0}}},"3":{".":{"0":{"df":1,"docs":{"88":{"tf":1.0}}},"df":0,"docs":{}},"2":{"df":2,"docs":{"36":{"tf":1.0},"42":{"tf":1.0}}},"df":2,"docs":{"12":{"tf":1.0},"18":{"tf":1.4142135623730951}},"f":{"a":{"4":{"df":0,"docs":{},"f":{"2":{"4":{"5":{"df":1,"docs":{"76":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}},"4":{"0":{"8":{"4":{"4":{"8":{"3":{"df":1,"docs":{"54":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"2":{"9":{"4":{"8":{"3":{"6":{"0":{"9":{"6":{"df":1,"docs":{"54":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"5":{"5":{"1":{"0":{"6":{"1":{"5":{"df":1,"docs":{"54":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"6":{"3":{"/":{"6":{"4":{"df":2,"docs":{"0":{"tf":1.0},"34":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"4":{"df":1,"docs":{"69":{"tf":1.0}}},"df":0,"docs":{}},"9":{"8":{"5":{"2":{"0":{"9":{"df":1,"docs":{"54":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"d":{"df":1,"docs":{"48":{"tf":1.7320508075688772}}},"df":0,"docs":{}}}}}}}}}},"df":0,"docs":{}}}},"a":{"b":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"49":{"tf":1.0}}}}},"df":0,"docs":{}}},"b":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"df":1,"docs":{"61":{"tf":1.0}}}}}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"v":{"df":3,"docs":{"36":{"tf":1.0},"76":{"tf":1.0},"84":{"tf":1.0}}}}},"c":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":1,"docs":{"56":{"tf":1.0}}}},"s":{"df":0,"docs":{},"s":{"df":2,"docs":{"37":{"tf":1.0},"67":{"tf":1.0}}}}}},"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":1,"docs":{"20":{"tf":1.0}}}}}},"k":{"df":0,"docs":{},"n":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"d":{"df":0,"docs":{},"g":{"df":1,"docs":{"62":{"tf":1.0}}}},"df":0,"docs":{}}}}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"76":{"tf":1.7320508075688772}}}},"v":{"df":2,"docs":{"18":{"tf":1.0},"23":{"tf":1.0}}}},"u":{"a":{"df":0,"docs":{},"l":{"df":4,"docs":{"18":{"tf":1.0},"32":{"tf":1.0},"72":{"tf":1.0},"77":{"tf":1.0}}}},"df":0,"docs":{}}}},"d":{"d":{"df":2,"docs":{"59":{"tf":1.4142135623730951},"61":{"tf":1.0}},"i":{"df":0,"docs":{},"t":{"df":4,"docs":{"24":{"tf":1.0},"4":{"tf":1.0},"61":{"tf":1.4142135623730951},"69":{"tf":1.0}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{".":{"c":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"o":{"d":{"df":1,"docs":{"35":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":1,"docs":{"18":{"tf":1.4142135623730951}}}}}}},"df":1,"docs":{"59":{"tf":1.0}},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":1,"docs":{"49":{"tf":1.0}}}}},"v":{"a":{"df":0,"docs":{},"n":{"c":{"df":1,"docs":{"12":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"34":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{},"g":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"61":{"tf":1.0}},"s":{"df":0,"docs":{},"t":{"df":3,"docs":{"49":{"tf":1.0},"72":{"tf":1.0},"76":{"tf":1.4142135623730951}}}}}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"12":{"tf":1.4142135623730951}}}}}}}},"i":{"df":3,"docs":{"49":{"tf":1.4142135623730951},"61":{"tf":1.0},"62":{"tf":2.6457513110645907}},"m":{"df":4,"docs":{"11":{"tf":1.0},"75":{"tf":1.0},"87":{"tf":1.0},"89":{"tf":1.0}}}},"l":{"df":0,"docs":{},"g":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"m":{"df":1,"docs":{"49":{"tf":1.0}}}}}}}}},"i":{"a":{"df":0,"docs":{},"s":{"df":1,"docs":{"61":{"tf":1.0}}}},"df":0,"docs":{}},"l":{"df":0,"docs":{},"o":{"c":{"df":1,"docs":{"72":{"tf":1.0}}},"df":0,"docs":{},"w":{"df":7,"docs":{"26":{"tf":1.0},"27":{"tf":1.4142135623730951},"30":{"tf":1.0},"67":{"tf":1.0},"72":{"tf":1.0},"76":{"tf":1.0},"77":{"tf":1.0}}}}},"w":{"a":{"df":0,"docs":{},"y":{"df":10,"docs":{"18":{"tf":1.0},"36":{"tf":1.0},"38":{"tf":1.0},"40":{"tf":1.0},"47":{"tf":1.0},"59":{"tf":1.0},"61":{"tf":1.0},"68":{"tf":1.0},"75":{"tf":1.0},"85":{"tf":1.0}}}},"df":0,"docs":{}}},"m":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":4,"docs":{"0":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"34":{"tf":1.0}}}}}}},"n":{"df":0,"docs":{},"n":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"c":{"df":1,"docs":{"22":{"tf":1.0}}},"df":0,"docs":{}}}}},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":2,"docs":{"68":{"tf":1.0},"72":{"tf":1.0}}}}},"y":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"56":{"tf":1.0}}}}}},"p":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":1,"docs":{"40":{"tf":1.0}}}}},"df":0,"docs":{},"i":{"df":2,"docs":{"67":{"tf":1.0},"73":{"tf":1.4142135623730951}}},"p":{"df":1,"docs":{"88":{"tf":1.0}},"e":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"18":{"tf":1.0}}},"df":0,"docs":{}}},"l":{"df":0,"docs":{},"i":{"c":{"df":2,"docs":{"49":{"tf":1.4142135623730951},"5":{"tf":1.0}}},"df":7,"docs":{"12":{"tf":1.4142135623730951},"27":{"tf":1.0},"34":{"tf":1.0},"37":{"tf":1.0},"49":{"tf":1.0},"65":{"tf":1.0},"84":{"tf":1.0}}}},"r":{"df":0,"docs":{},"o":{"a":{"c":{"df":0,"docs":{},"h":{"df":2,"docs":{"63":{"tf":1.0},"77":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"74":{"tf":1.0}}}}}}}}},"r":{"b":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"30":{"tf":1.0}}}}},"df":0,"docs":{}}}}},"c":{"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":3,"docs":{"40":{"tf":1.0},"63":{"tf":1.0},"69":{"tf":1.0}}}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"u":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":4,"docs":{"30":{"tf":1.0},"36":{"tf":1.0},"40":{"tf":1.7320508075688772},"53":{"tf":1.0}}}}}}}},"m":{"df":1,"docs":{"72":{"tf":1.0}}},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"d":{"df":3,"docs":{"49":{"tf":1.0},"72":{"tf":1.4142135623730951},"86":{"tf":1.0}}},"df":0,"docs":{}}}},"t":{"df":1,"docs":{"72":{"tf":1.0}},"i":{"df":0,"docs":{},"f":{"a":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"16":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"s":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":4,"docs":{"55":{"tf":1.0},"58":{"tf":1.0},"61":{"tf":1.0},"62":{"tf":1.0}}}},"df":0,"docs":{}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"b":{"df":0,"docs":{},"l":{"df":5,"docs":{"16":{"tf":1.0},"36":{"tf":1.0},"4":{"tf":1.0},"40":{"tf":1.7320508075688772},"83":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"t":{"df":2,"docs":{"68":{"tf":1.0},"76":{"tf":1.0}}}},"t":{"df":1,"docs":{"73":{"tf":1.0}}}},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":2,"docs":{"61":{"tf":1.0},"62":{"tf":1.4142135623730951}}}}},"u":{"df":0,"docs":{},"m":{"df":2,"docs":{"40":{"tf":1.0},"47":{"tf":1.0}},"p":{"df":0,"docs":{},"t":{"df":1,"docs":{"72":{"tf":1.0}}}}}}},"t":{"df":1,"docs":{"66":{"tf":1.0}}}},"u":{"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"c":{"df":1,"docs":{"1":{"tf":1.0}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"28":{"tf":1.0}}}}}}},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"36":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"t":{"df":2,"docs":{"53":{"tf":1.4142135623730951},"59":{"tf":1.0}}}},"df":0,"docs":{}}}}},"v":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":5,"docs":{"14":{"tf":1.0},"21":{"tf":1.0},"22":{"tf":1.0},"47":{"tf":1.0},"72":{"tf":1.0}}}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"i":{"d":{"df":3,"docs":{"53":{"tf":1.0},"59":{"tf":1.0},"61":{"tf":1.7320508075688772}}},"df":0,"docs":{}}}},"w":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"33":{"tf":1.0}}}},"df":0,"docs":{}}},"b":{"a":{"c":{"df":0,"docs":{},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"d":{"df":2,"docs":{"12":{"tf":1.0},"63":{"tf":1.0}}},"df":0,"docs":{}}},"w":{"a":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"73":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"n":{"c":{"df":2,"docs":{"63":{"tf":1.0},"76":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"k":{"df":1,"docs":{"72":{"tf":1.0}}}}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"88":{"tf":1.0}}}}}}},"s":{"df":0,"docs":{},"e":{"df":5,"docs":{"17":{"tf":1.0},"47":{"tf":1.0},"48":{"tf":1.0},"49":{"tf":1.0},"72":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"=":{"1":{"0":{"3":{"0":{"6":{"3":{"/":{"1":{"5":{"7":{"2":{"8":{"6":{"4":{"df":1,"docs":{"54":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"i":{"c":{"df":1,"docs":{"12":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":2,"docs":{"48":{"tf":1.0},"53":{"tf":1.0}}}}},"h":{"a":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":2,"docs":{"47":{"tf":1.0},"61":{"tf":1.0}}}}}}},"df":0,"docs":{}},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":2,"docs":{"72":{"tf":1.0},"88":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"w":{"df":3,"docs":{"18":{"tf":1.0},"36":{"tf":1.0},"89":{"tf":1.0}}}}},"n":{"c":{"df":0,"docs":{},"h":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"k":{"df":2,"docs":{"58":{"tf":1.0},"72":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"49":{"tf":1.0}}}}}}},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"61":{"tf":1.0}}}},"t":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"49":{"tf":1.0}}}}},"w":{"df":0,"docs":{},"e":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":5,"docs":{"12":{"tf":1.0},"32":{"tf":1.0},"47":{"tf":1.0},"63":{"tf":1.0},"69":{"tf":1.0}}}}}}},"y":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"d":{"df":2,"docs":{"49":{"tf":1.0},"74":{"tf":1.0}}},"df":0,"docs":{}}}}},"i":{"df":0,"docs":{},"g":{"df":1,"docs":{"67":{"tf":1.0}}},"n":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":7,"docs":{"5":{"tf":1.0},"50":{"tf":1.0},"64":{"tf":1.0},"65":{"tf":1.4142135623730951},"68":{"tf":1.0},"7":{"tf":1.4142135623730951},"78":{"tf":1.0}}}}},"df":1,"docs":{"19":{"tf":1.0}}},"t":{"df":3,"docs":{"36":{"tf":1.0},"59":{"tf":1.0},"69":{"tf":1.4142135623730951}},"w":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":1,"docs":{"76":{"tf":1.7320508075688772}}}}}}},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"62":{"tf":1.0}}}}},"df":0,"docs":{}}},"o":{"b":{"b":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":1,"docs":{"46":{"tf":1.0}}}}}}},"df":0,"docs":{}},"df":6,"docs":{"18":{"tf":1.7320508075688772},"32":{"tf":1.4142135623730951},"46":{"tf":1.0},"64":{"tf":1.0},"65":{"tf":1.0},"89":{"tf":1.0}},"h":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"df":1,"docs":{"46":{"tf":1.0}}}}},"df":0,"docs":{}}},"c":{"df":0,"docs":{},"k":{"c":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":5,"docs":{"49":{"tf":1.0},"50":{"tf":1.4142135623730951},"72":{"tf":1.0},"73":{"tf":1.0},"77":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":1,"docs":{"40":{"tf":1.7320508075688772}}}},"df":0,"docs":{}}},"o":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"72":{"tf":1.0}}}},"o":{"df":0,"docs":{},"k":{"df":2,"docs":{"0":{"tf":1.0},"3":{"tf":1.4142135623730951}}},"l":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"n":{"df":1,"docs":{"26":{"tf":1.0}}}},"df":0,"docs":{}}}},"t":{"df":0,"docs":{},"h":{"df":2,"docs":{"18":{"tf":1.0},"32":{"tf":1.0}}}},"u":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"67":{"tf":1.0}}},"df":0,"docs":{}}}},"r":{"a":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"h":{"df":1,"docs":{"60":{"tf":1.7320508075688772}}}},"df":0,"docs":{}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"78":{"tf":1.0}}}}}}}},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"65":{"tf":1.0}}}},"df":0,"docs":{}}}}}},"u":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":5,"docs":{"14":{"tf":1.0},"36":{"tf":1.4142135623730951},"37":{"tf":1.4142135623730951},"40":{"tf":1.4142135623730951},"67":{"tf":1.4142135623730951}}}}}},"g":{"df":5,"docs":{"23":{"tf":1.0},"74":{"tf":1.0},"75":{"tf":1.4142135623730951},"76":{"tf":1.0},"77":{"tf":1.0}},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"x":{"df":1,"docs":{"85":{"tf":1.0}}}}}},"i":{"d":{"df":0,"docs":{},"l":{"df":1,"docs":{"10":{"tf":1.0}}}},"df":0,"docs":{},"l":{"d":{"df":8,"docs":{"10":{"tf":1.0},"57":{"tf":1.0},"58":{"tf":1.0},"6":{"tf":1.0},"65":{"tf":1.7320508075688772},"68":{"tf":2.0},"74":{"tf":1.0},"79":{"tf":2.449489742783178}},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"66":{"tf":1.0},"68":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"68":{"tf":1.0}}}},"t":{"df":1,"docs":{"68":{"tf":1.0}},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"68":{"tf":1.0}}}}}}},"n":{"d":{"df":0,"docs":{},"l":{"df":1,"docs":{"65":{"tf":1.0}}}},"df":0,"docs":{}},"s":{"df":0,"docs":{},"i":{"df":1,"docs":{"49":{"tf":1.0}}}}},"y":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"o":{"d":{"df":3,"docs":{"18":{"tf":1.0},"35":{"tf":1.0},"72":{"tf":2.23606797749979}}},"df":0,"docs":{}}},"df":2,"docs":{"37":{"tf":1.0},"67":{"tf":1.4142135623730951}}}}}},"c":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"_":{"d":{"a":{"df":0,"docs":{},"t":{"a":{"_":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"y":{"(":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":1,"docs":{"54":{"tf":1.0}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"s":{"df":1,"docs":{"54":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"18":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"d":{"a":{"df":0,"docs":{},"t":{"a":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":1,"docs":{"38":{"tf":1.0}}}}}},"df":2,"docs":{"38":{"tf":1.0},"76":{"tf":1.0}},"l":{"df":0,"docs":{},"o":{"a":{"d":{"df":1,"docs":{"38":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":6,"docs":{"0":{"tf":1.0},"18":{"tf":1.0},"32":{"tf":1.0},"34":{"tf":1.0},"53":{"tf":1.0},"76":{"tf":1.4142135623730951}}}},"n":{"df":0,"docs":{},"’":{"df":0,"docs":{},"t":{"df":1,"docs":{"49":{"tf":1.0}}}}},"p":{"df":1,"docs":{"37":{"tf":1.0}},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":2,"docs":{"62":{"tf":1.4142135623730951},"69":{"tf":1.0}}}}}},"r":{"df":0,"docs":{},"e":{"df":2,"docs":{"18":{"tf":1.0},"63":{"tf":1.0}},"f":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"0":{"tf":1.0}}}}}}}},"g":{"df":0,"docs":{},"o":{".":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{"df":1,"docs":{"59":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":1,"docs":{"59":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"e":{"df":5,"docs":{"18":{"tf":2.0},"45":{"tf":1.0},"46":{"tf":1.0},"76":{"tf":1.4142135623730951},"77":{"tf":1.4142135623730951}}}},"u":{"df":0,"docs":{},"s":{"df":1,"docs":{"77":{"tf":1.0}}}},"v":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"37":{"tf":1.0}}}},"df":0,"docs":{}}}},"d":{"df":1,"docs":{"74":{"tf":1.0}}},"df":1,"docs":{"49":{"tf":1.0}},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"76":{"tf":1.0}}}},"df":0,"docs":{}}}}},"h":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":3,"docs":{"32":{"tf":1.0},"65":{"tf":1.0},"72":{"tf":1.4142135623730951}}}},"n":{"c":{"df":2,"docs":{"49":{"tf":1.0},"58":{"tf":1.0}}},"df":0,"docs":{},"g":{"df":6,"docs":{"18":{"tf":1.0},"3":{"tf":1.0},"34":{"tf":1.0},"59":{"tf":1.0},"60":{"tf":1.4142135623730951},"76":{"tf":1.4142135623730951}}}},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":4,"docs":{"11":{"tf":1.0},"55":{"tf":1.0},"74":{"tf":1.0},"83":{"tf":1.0}}}}}},"r":{"df":1,"docs":{"29":{"tf":1.0}}}},"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"k":{"df":2,"docs":{"67":{"tf":1.0},"85":{"tf":1.0}}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"49":{"tf":1.0}}},"df":0,"docs":{}}}},"i":{"df":2,"docs":{"58":{"tf":1.0},"60":{"tf":1.4142135623730951}},"r":{"c":{"df":0,"docs":{},"u":{"df":0,"docs":{},"m":{"df":0,"docs":{},"v":{"df":1,"docs":{"65":{"tf":1.0}}}}}},"df":0,"docs":{}}},"l":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":1,"docs":{"5":{"tf":1.0}}}}},"df":0,"docs":{},"i":{"df":2,"docs":{"11":{"tf":2.0},"18":{"tf":1.0}},"p":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":1,"docs":{"61":{"tf":1.0}}}}}},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":1,"docs":{"74":{"tf":1.0}}}},"s":{"df":0,"docs":{},"e":{"df":3,"docs":{"11":{"tf":1.0},"72":{"tf":1.0},"75":{"tf":1.0}}}}}},"o":{"d":{"df":0,"docs":{},"e":{"b":{"a":{"df":0,"docs":{},"s":{"df":4,"docs":{"55":{"tf":1.0},"58":{"tf":1.0},"59":{"tf":1.4142135623730951},"62":{"tf":1.7320508075688772}}}},"df":0,"docs":{}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":1,"docs":{"39":{"tf":1.0}}}}}},"df":31,"docs":{"0":{"tf":1.0},"12":{"tf":1.4142135623730951},"13":{"tf":1.0},"14":{"tf":1.0},"17":{"tf":1.0},"18":{"tf":1.4142135623730951},"19":{"tf":1.0},"32":{"tf":3.0},"33":{"tf":1.0},"34":{"tf":1.0},"36":{"tf":1.0},"38":{"tf":1.0},"39":{"tf":1.0},"4":{"tf":1.0},"40":{"tf":2.23606797749979},"5":{"tf":1.0},"50":{"tf":1.4142135623730951},"6":{"tf":1.0},"61":{"tf":1.4142135623730951},"62":{"tf":1.0},"63":{"tf":1.0},"64":{"tf":1.4142135623730951},"65":{"tf":1.7320508075688772},"66":{"tf":1.4142135623730951},"67":{"tf":1.0},"72":{"tf":2.0},"74":{"tf":1.0},"75":{"tf":1.0},"76":{"tf":1.4142135623730951},"86":{"tf":1.0},"89":{"tf":1.4142135623730951}},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":2,"docs":{"47":{"tf":1.0},"48":{"tf":1.0}}}}},"s":{"df":1,"docs":{"32":{"tf":1.0}}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"76":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}}},"m":{"b":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":2,"docs":{"5":{"tf":1.0},"76":{"tf":1.4142135623730951}}}}},"df":0,"docs":{},"e":{"df":2,"docs":{"50":{"tf":1.0},"74":{"tf":1.0}}},"m":{"a":{"df":0,"docs":{},"n":{"d":{"df":2,"docs":{"19":{"tf":1.0},"30":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"61":{"tf":2.0}}}}},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"49":{"tf":1.0}}}}},"p":{"a":{"df":0,"docs":{},"r":{"df":2,"docs":{"31":{"tf":1.0},"37":{"tf":1.0}},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"0":{"tf":1.0}}}}}}},"t":{"df":8,"docs":{"24":{"tf":1.0},"63":{"tf":1.0},"67":{"tf":1.0},"73":{"tf":1.0},"75":{"tf":1.4142135623730951},"76":{"tf":1.0},"79":{"tf":1.0},"88":{"tf":1.0}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":46,"docs":{"0":{"tf":1.0},"12":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"16":{"tf":1.0},"18":{"tf":2.23606797749979},"19":{"tf":1.0},"22":{"tf":1.0},"24":{"tf":1.0},"25":{"tf":1.0},"3":{"tf":1.0},"36":{"tf":1.0},"37":{"tf":1.0},"4":{"tf":1.7320508075688772},"45":{"tf":1.0},"46":{"tf":1.0},"47":{"tf":1.7320508075688772},"49":{"tf":1.0},"5":{"tf":2.0},"54":{"tf":1.0},"55":{"tf":1.0},"56":{"tf":1.0},"57":{"tf":1.0},"58":{"tf":1.0},"59":{"tf":1.0},"6":{"tf":1.7320508075688772},"62":{"tf":1.0},"63":{"tf":2.0},"64":{"tf":1.7320508075688772},"65":{"tf":1.4142135623730951},"66":{"tf":1.7320508075688772},"67":{"tf":1.0},"68":{"tf":1.4142135623730951},"70":{"tf":1.0},"72":{"tf":2.23606797749979},"73":{"tf":1.0},"74":{"tf":1.0},"75":{"tf":1.4142135623730951},"76":{"tf":1.0},"77":{"tf":1.0},"78":{"tf":1.4142135623730951},"8":{"tf":1.0},"80":{"tf":1.0},"88":{"tf":1.4142135623730951},"89":{"tf":1.0},"9":{"tf":1.0}}}},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":3,"docs":{"11":{"tf":1.0},"72":{"tf":1.0},"89":{"tf":1.0}}},"x":{"df":2,"docs":{"49":{"tf":1.0},"77":{"tf":1.4142135623730951}}}},"i":{"c":{"df":1,"docs":{"59":{"tf":1.0}}},"df":0,"docs":{}}},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"5":{"tf":1.4142135623730951}}},"s":{"df":1,"docs":{"49":{"tf":1.0}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":2,"docs":{"58":{"tf":1.0},"77":{"tf":1.0}}}}}}}},"t":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"4":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}},"u":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"49":{"tf":1.0}}}}}}},"df":1,"docs":{"72":{"tf":1.0}}}}}},"n":{"c":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"40":{"tf":1.0}}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":1,"docs":{"58":{"tf":1.0}}}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":7,"docs":{"13":{"tf":1.0},"14":{"tf":1.0},"24":{"tf":1.0},"25":{"tf":1.0},"27":{"tf":1.7320508075688772},"29":{"tf":1.0},"71":{"tf":1.4142135623730951}}}}}},"l":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"61":{"tf":1.0}}}},"df":0,"docs":{}}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"q":{"df":0,"docs":{},"u":{"df":1,"docs":{"18":{"tf":1.0}},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"14":{"tf":1.0}}}}}}}}},"i":{"d":{"df":5,"docs":{"59":{"tf":1.0},"61":{"tf":1.0},"65":{"tf":1.0},"73":{"tf":1.0},"87":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"49":{"tf":1.0}}}}},"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":2,"docs":{"62":{"tf":1.0},"72":{"tf":1.0}}}}},"t":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":5,"docs":{"14":{"tf":1.0},"40":{"tf":1.0},"42":{"tf":1.0},"44":{"tf":1.0},"61":{"tf":1.0}}}}},"df":0,"docs":{},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"53":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"u":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":6,"docs":{"32":{"tf":1.4142135623730951},"38":{"tf":1.0},"39":{"tf":1.0},"40":{"tf":1.7320508075688772},"48":{"tf":1.7320508075688772},"53":{"tf":1.0}}}}}},"df":0,"docs":{}}}}},"t":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":3,"docs":{"36":{"tf":1.0},"40":{"tf":1.0},"5":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"3":{"tf":1.0}}}},"x":{"df":0,"docs":{},"t":{"df":2,"docs":{"62":{"tf":1.0},"66":{"tf":2.0}}}}},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":32,"docs":{"0":{"tf":2.0},"12":{"tf":1.0},"13":{"tf":1.7320508075688772},"14":{"tf":2.0},"18":{"tf":2.0},"2":{"tf":1.4142135623730951},"27":{"tf":1.4142135623730951},"32":{"tf":1.4142135623730951},"34":{"tf":1.0},"36":{"tf":1.0},"37":{"tf":1.7320508075688772},"4":{"tf":1.4142135623730951},"40":{"tf":2.0},"41":{"tf":1.0},"42":{"tf":1.0},"47":{"tf":1.0},"48":{"tf":1.4142135623730951},"49":{"tf":1.4142135623730951},"50":{"tf":1.4142135623730951},"52":{"tf":1.0},"53":{"tf":1.4142135623730951},"54":{"tf":1.4142135623730951},"6":{"tf":1.0},"63":{"tf":1.4142135623730951},"65":{"tf":2.0},"67":{"tf":1.0},"72":{"tf":2.23606797749979},"73":{"tf":1.0},"75":{"tf":1.4142135623730951},"76":{"tf":2.0},"86":{"tf":1.0},"88":{"tf":1.4142135623730951}},"s":{".":{"df":0,"docs":{},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"k":{"a":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{".":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":1,"docs":{"2":{"tf":1.0}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"’":{"df":2,"docs":{"13":{"tf":1.0},"14":{"tf":1.0}}}}},"df":0,"docs":{}},"df":0,"docs":{},"i":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":5,"docs":{"13":{"tf":1.0},"14":{"tf":1.0},"56":{"tf":1.0},"60":{"tf":1.4142135623730951},"62":{"tf":2.0}},"o":{"df":0,"docs":{},"r":{"df":5,"docs":{"1":{"tf":1.0},"55":{"tf":1.0},"56":{"tf":1.0},"62":{"tf":1.0},"74":{"tf":1.0}}}}}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"l":{"df":4,"docs":{"13":{"tf":1.0},"52":{"tf":1.0},"67":{"tf":1.0},"79":{"tf":1.0}}}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":3,"docs":{"49":{"tf":1.0},"50":{"tf":1.0},"52":{"tf":1.0}}}}}}},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":3,"docs":{"62":{"tf":1.0},"74":{"tf":1.4142135623730951},"76":{"tf":1.0}}}},"df":0,"docs":{},"s":{"df":0,"docs":{},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"d":{"df":4,"docs":{"18":{"tf":1.0},"26":{"tf":1.0},"27":{"tf":1.4142135623730951},"29":{"tf":1.0}}},"df":0,"docs":{}}}}}}}},"s":{"df":0,"docs":{},"t":{"df":3,"docs":{"13":{"tf":1.4142135623730951},"14":{"tf":1.7320508075688772},"40":{"tf":1.0}}}},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"61":{"tf":1.0}},"p":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":1,"docs":{"76":{"tf":1.0}}}}},"df":0,"docs":{}}}}}},"p":{"df":0,"docs":{},"l":{"df":1,"docs":{"49":{"tf":1.0}}}},"r":{"df":0,"docs":{},"s":{"df":1,"docs":{"49":{"tf":1.0}}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"55":{"tf":1.0}}}}}},"p":{"df":0,"docs":{},"u":{"df":2,"docs":{"71":{"tf":1.4142135623730951},"72":{"tf":1.4142135623730951}}}},"r":{"a":{"df":0,"docs":{},"f":{"df":0,"docs":{},"t":{"df":1,"docs":{"40":{"tf":1.0}}}},"t":{"df":0,"docs":{},"e":{"df":3,"docs":{"59":{"tf":2.449489742783178},"66":{"tf":1.7320508075688772},"68":{"tf":1.4142135623730951}},"s":{"/":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"g":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"/":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"s":{"/":{"df":0,"docs":{},"f":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"p":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{".":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":1,"docs":{"19":{"tf":1.0}}}}}},"df":0,"docs":{}}}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"t":{"df":4,"docs":{"40":{"tf":1.7320508075688772},"59":{"tf":1.0},"62":{"tf":1.0},"77":{"tf":1.0}},"e":{"2":{"df":1,"docs":{"40":{"tf":1.0}}},"df":0,"docs":{}},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"77":{"tf":1.0}}}}}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":4,"docs":{"58":{"tf":1.0},"68":{"tf":1.4142135623730951},"78":{"tf":1.4142135623730951},"80":{"tf":1.4142135623730951}}}}},"u":{"c":{"df":0,"docs":{},"i":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"65":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"86":{"tf":1.0}}}}}}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"df":3,"docs":{"68":{"tf":1.0},"69":{"tf":1.4142135623730951},"89":{"tf":1.0}}}}}}}},"d":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"p":{"df":7,"docs":{"1":{"tf":1.0},"18":{"tf":1.0},"31":{"tf":1.0},"36":{"tf":1.0},"49":{"tf":1.4142135623730951},"85":{"tf":1.0},"88":{"tf":1.4142135623730951}}}},"t":{"a":{"_":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"54":{"tf":1.4142135623730951}}}}},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":1,"docs":{"54":{"tf":1.4142135623730951}}}}}},"df":6,"docs":{"18":{"tf":1.0},"32":{"tf":1.0},"46":{"tf":1.0},"54":{"tf":2.0},"67":{"tf":1.0},"76":{"tf":1.4142135623730951}},"o":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":2,"docs":{"40":{"tf":1.0},"41":{"tf":1.0}}}}}}}},"s":{"df":2,"docs":{"40":{"tf":1.0},"42":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{},"e":{"a":{"d":{"df":1,"docs":{"49":{"tf":1.0}}},"df":0,"docs":{},"l":{"df":1,"docs":{"36":{"tf":1.0}}}},"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"_":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":0,"docs":{},"p":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"_":{"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"16":{"tf":1.0}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}},"df":6,"docs":{"16":{"tf":1.7320508075688772},"17":{"tf":1.7320508075688772},"26":{"tf":1.0},"30":{"tf":1.0},"50":{"tf":1.0},"54":{"tf":1.0}}}}},"c":{"df":0,"docs":{},"i":{"d":{"df":2,"docs":{"18":{"tf":1.0},"77":{"tf":1.0}}},"df":0,"docs":{},"s":{"df":3,"docs":{"61":{"tf":1.0},"72":{"tf":1.0},"88":{"tf":1.0}}}},"l":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"76":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":1,"docs":{"66":{"tf":1.0}}}}}}},"d":{"df":0,"docs":{},"i":{"c":{"df":2,"docs":{"59":{"tf":1.0},"66":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"f":{"a":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":5,"docs":{"12":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"15":{"tf":1.0},"17":{"tf":1.0}}}}}},"df":0,"docs":{},"i":{"df":1,"docs":{"49":{"tf":1.0}},"n":{"df":2,"docs":{"74":{"tf":1.0},"76":{"tf":2.0}}}},"u":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"0":{"tf":1.0}}}},"df":0,"docs":{}}}},"g":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":2,"docs":{"61":{"tf":1.0},"62":{"tf":1.0}}}}},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"g":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"c":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"18":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"t":{"df":1,"docs":{"61":{"tf":1.0}}}},"i":{"df":0,"docs":{},"v":{"df":1,"docs":{"89":{"tf":1.0}}}}},"n":{"df":0,"docs":{},"i":{"df":1,"docs":{"60":{"tf":1.0}}}},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"d":{"df":6,"docs":{"18":{"tf":1.4142135623730951},"59":{"tf":3.0},"65":{"tf":1.0},"68":{"tf":1.7320508075688772},"79":{"tf":1.7320508075688772},"8":{"tf":1.0}}},"df":0,"docs":{}}},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"y":{"df":5,"docs":{"18":{"tf":3.1622776601683795},"31":{"tf":1.0},"32":{"tf":1.7320508075688772},"40":{"tf":2.23606797749979},"86":{"tf":1.0}}}}},"r":{"df":0,"docs":{},"e":{"c":{"df":1,"docs":{"49":{"tf":1.0}}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":1,"docs":{"48":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"n":{"df":3,"docs":{"49":{"tf":1.0},"61":{"tf":1.0},"72":{"tf":1.4142135623730951}}}},"r":{"df":1,"docs":{"50":{"tf":1.0}}}},"t":{"df":1,"docs":{"76":{"tf":1.0}}}},"t":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":2,"docs":{"11":{"tf":1.0},"77":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"37":{"tf":1.0}}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"65":{"tf":1.0}}}}}}}}}}},"v":{"df":2,"docs":{"50":{"tf":1.0},"59":{"tf":1.4142135623730951}},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":10,"docs":{"1":{"tf":1.4142135623730951},"16":{"tf":1.0},"17":{"tf":1.0},"20":{"tf":1.0},"30":{"tf":1.0},"31":{"tf":1.0},"49":{"tf":1.0},"55":{"tf":1.0},"58":{"tf":1.4142135623730951},"89":{"tf":1.0}}}}}}}},"i":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"31":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":11,"docs":{"0":{"tf":2.23606797749979},"1":{"tf":1.0},"12":{"tf":1.0},"31":{"tf":1.4142135623730951},"33":{"tf":1.0},"36":{"tf":1.0},"37":{"tf":1.0},"40":{"tf":1.4142135623730951},"47":{"tf":1.7320508075688772},"75":{"tf":1.0},"83":{"tf":1.0}},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":4,"docs":{"32":{"tf":1.0},"65":{"tf":1.0},"76":{"tf":3.0},"77":{"tf":2.0}}}}}}}},"i":{"c":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"44":{"tf":1.0}}}}}}},"df":0,"docs":{}}}},"r":{"df":2,"docs":{"16":{"tf":1.0},"59":{"tf":1.0}},"e":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"19":{"tf":1.0}}}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":4,"docs":{"16":{"tf":1.0},"18":{"tf":1.4142135623730951},"51":{"tf":1.0},"59":{"tf":1.0}}}}}}},"df":0,"docs":{}}},"s":{"a":{"b":{"df":0,"docs":{},"l":{"df":2,"docs":{"17":{"tf":1.0},"18":{"tf":1.0}}}},"df":0,"docs":{}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"g":{"df":2,"docs":{"18":{"tf":1.4142135623730951},"40":{"tf":1.0}}}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":2,"docs":{"60":{"tf":1.0},"62":{"tf":1.0}}}}}},"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":2,"docs":{"68":{"tf":1.0},"9":{"tf":1.0}}}}},"df":0,"docs":{}}}}}},"o":{"c":{"df":1,"docs":{"61":{"tf":1.0}},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"80":{"tf":1.0}}}}}}}},"u":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":2,"docs":{"3":{"tf":1.0},"8":{"tf":1.0}}}}}}}},"df":1,"docs":{"0":{"tf":1.0}},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"n":{"df":0,"docs":{},"’":{"df":0,"docs":{},"t":{"df":5,"docs":{"19":{"tf":1.0},"34":{"tf":1.0},"59":{"tf":1.0},"61":{"tf":1.0},"67":{"tf":1.0}}}}}}},"m":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"69":{"tf":1.0}}}}},"df":0,"docs":{}},"n":{"df":0,"docs":{},"e":{"df":1,"docs":{"18":{"tf":1.0}}},"’":{"df":0,"docs":{},"t":{"df":5,"docs":{"36":{"tf":1.0},"59":{"tf":1.0},"61":{"tf":1.4142135623730951},"68":{"tf":1.0},"82":{"tf":1.0}}}}},"w":{"df":0,"docs":{},"n":{"df":2,"docs":{"50":{"tf":1.0},"72":{"tf":1.0}}}}},"r":{"df":1,"docs":{"88":{"tf":1.0}},"i":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":3,"docs":{"19":{"tf":1.0},"5":{"tf":1.0},"64":{"tf":1.0}}}}}},"o":{"df":0,"docs":{},"p":{"df":1,"docs":{"87":{"tf":1.4142135623730951}}}}},"u":{"df":0,"docs":{},"e":{"df":7,"docs":{"13":{"tf":1.0},"14":{"tf":1.0},"18":{"tf":1.7320508075688772},"40":{"tf":1.0},"65":{"tf":1.0},"69":{"tf":1.0},"75":{"tf":1.0}}},"m":{"df":0,"docs":{},"p":{"df":1,"docs":{"16":{"tf":1.0}}}},"r":{"df":0,"docs":{},"e":{"df":3,"docs":{"18":{"tf":1.4142135623730951},"68":{"tf":1.0},"8":{"tf":1.0}}}}},"y":{"df":0,"docs":{},"n":{"a":{"df":0,"docs":{},"m":{"df":2,"docs":{"14":{"tf":1.0},"65":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{},"e":{"a":{"c":{"df":0,"docs":{},"h":{"df":2,"docs":{"49":{"tf":1.0},"76":{"tf":1.4142135623730951}}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"77":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"i":{"df":1,"docs":{"5":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":2,"docs":{"49":{"tf":1.0},"61":{"tf":1.0}}}}}}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"s":{"df":0,"docs":{},"y":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":1,"docs":{"88":{"tf":1.0}}}}}}}}}},"d":{"df":0,"docs":{},"g":{"df":1,"docs":{"88":{"tf":1.0}}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":2,"docs":{"72":{"tf":1.0},"76":{"tf":1.0}}}},"df":0,"docs":{}},"i":{"c":{"df":0,"docs":{},"i":{"df":1,"docs":{"72":{"tf":1.0}}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":4,"docs":{"49":{"tf":1.0},"61":{"tf":1.0},"63":{"tf":1.0},"88":{"tf":1.0}}}}}}},"l":{"df":0,"docs":{},"f":{"df":5,"docs":{"16":{"tf":1.0},"18":{"tf":1.4142135623730951},"64":{"tf":1.4142135623730951},"71":{"tf":1.0},"78":{"tf":1.0}}},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":2,"docs":{"77":{"tf":1.0},"88":{"tf":1.0}}}}}}},"m":{"b":{"df":0,"docs":{},"e":{"d":{"df":1,"docs":{"72":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":7,"docs":{"18":{"tf":1.0},"32":{"tf":1.0},"36":{"tf":1.0},"64":{"tf":1.0},"66":{"tf":1.0},"67":{"tf":1.4142135623730951},"89":{"tf":1.4142135623730951}}}},"p":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"y":{"df":1,"docs":{"65":{"tf":1.0}}}}},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"54":{"tf":1.0}}}}},"s":{"c":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":3,"docs":{"68":{"tf":1.0},"7":{"tf":1.0},"79":{"tf":1.4142135623730951}}}}}}}}},"d":{"df":0,"docs":{},"k":{"/":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":0,"docs":{},"s":{"d":{"df":0,"docs":{},"k":{"_":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"v":{".":{"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"df":1,"docs":{"79":{"tf":1.0}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":1,"docs":{"79":{"tf":1.0}}}},"df":0,"docs":{}},"u":{"df":0,"docs":{},"l":{"df":3,"docs":{"14":{"tf":1.0},"37":{"tf":1.0},"67":{"tf":1.0}}}}},"n":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"26":{"tf":1.0}}}},"df":0,"docs":{}},"c":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"s":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":2,"docs":{"58":{"tf":1.0},"66":{"tf":1.0}}}}}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"g":{"df":1,"docs":{"74":{"tf":1.0}}}},"df":0,"docs":{}}}}},"d":{"df":1,"docs":{"49":{"tf":1.4142135623730951}},"i":{"a":{"df":0,"docs":{},"n":{"df":1,"docs":{"67":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":2,"docs":{"49":{"tf":1.0},"63":{"tf":1.0}}}},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"df":1,"docs":{"61":{"tf":1.0}}}}}}},"j":{"df":0,"docs":{},"o":{"df":0,"docs":{},"y":{"df":1,"docs":{"62":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":2,"docs":{"61":{"tf":1.0},"62":{"tf":1.0}}}}}},"s":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":3,"docs":{"60":{"tf":1.0},"65":{"tf":1.0},"76":{"tf":1.4142135623730951}}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"r":{"df":1,"docs":{"72":{"tf":1.0}}}},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"88":{"tf":1.0}}},"y":{"df":0,"docs":{},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"5":{"tf":1.0}}}}}}}}}},"v":{"df":1,"docs":{"79":{"tf":1.0}},"i":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":6,"docs":{"50":{"tf":1.0},"52":{"tf":1.0},"69":{"tf":1.0},"73":{"tf":1.7320508075688772},"78":{"tf":1.0},"79":{"tf":1.4142135623730951}}}}}}}},"q":{"df":0,"docs":{},"u":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"32":{"tf":1.0}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"l":{"df":2,"docs":{"4":{"tf":1.0},"72":{"tf":1.0}}}},"df":0,"docs":{}}}}},"r":{"df":0,"docs":{},"r":{"(":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{":":{":":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"(":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"d":{"a":{"df":0,"docs":{},"t":{"a":{"df":1,"docs":{"54":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":5,"docs":{"36":{"tf":1.0},"37":{"tf":1.0},"45":{"tf":1.0},"46":{"tf":1.0},"76":{"tf":1.0}}}}}},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"u":{"df":0,"docs":{},"m":{"/":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"d":{"/":{"b":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"/":{":":{"$":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"74":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":13,"docs":{"0":{"tf":1.0},"11":{"tf":1.0},"31":{"tf":1.0},"37":{"tf":1.0},"4":{"tf":1.0},"46":{"tf":1.0},"6":{"tf":1.0},"63":{"tf":1.4142135623730951},"74":{"tf":1.7320508075688772},"75":{"tf":1.4142135623730951},"76":{"tf":2.23606797749979},"8":{"tf":1.0},"88":{"tf":1.0}}}}}}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":4,"docs":{"49":{"tf":1.0},"62":{"tf":1.0},"72":{"tf":1.0},"88":{"tf":1.0}},"t":{"df":0,"docs":{},"u":{"df":2,"docs":{"13":{"tf":1.0},"14":{"tf":1.0}}}}}},"m":{"df":19,"docs":{"0":{"tf":1.4142135623730951},"1":{"tf":1.0},"14":{"tf":1.4142135623730951},"31":{"tf":1.4142135623730951},"32":{"tf":1.0},"37":{"tf":1.4142135623730951},"4":{"tf":1.0},"40":{"tf":1.4142135623730951},"45":{"tf":1.0},"48":{"tf":1.0},"49":{"tf":1.7320508075688772},"67":{"tf":2.0},"69":{"tf":1.4142135623730951},"72":{"tf":2.23606797749979},"74":{"tf":1.0},"75":{"tf":1.0},"76":{"tf":2.6457513110645907},"82":{"tf":1.4142135623730951},"86":{"tf":1.0}}}},"x":{"a":{"c":{"df":0,"docs":{},"t":{"df":3,"docs":{"18":{"tf":1.0},"71":{"tf":1.0},"77":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":2,"docs":{"65":{"tf":1.0},"76":{"tf":1.0}}}}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":13,"docs":{"0":{"tf":1.0},"18":{"tf":1.0},"48":{"tf":1.0},"49":{"tf":1.4142135623730951},"5":{"tf":1.0},"54":{"tf":1.0},"58":{"tf":1.0},"60":{"tf":1.0},"65":{"tf":1.0},"76":{"tf":1.4142135623730951},"77":{"tf":1.0},"79":{"tf":1.0},"80":{"tf":1.0}}}}}},"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":1,"docs":{"49":{"tf":1.0}}},"p":{"df":0,"docs":{},"t":{"df":1,"docs":{"60":{"tf":1.0}}}}}},"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":15,"docs":{"12":{"tf":1.7320508075688772},"13":{"tf":1.0},"14":{"tf":1.0},"15":{"tf":1.0},"36":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.4142135623730951},"52":{"tf":1.4142135623730951},"54":{"tf":1.0},"72":{"tf":1.4142135623730951},"76":{"tf":2.449489742783178},"77":{"tf":1.0},"78":{"tf":1.0},"79":{"tf":1.0},"80":{"tf":1.0}}}}},"df":0,"docs":{}},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":2,"docs":{"11":{"tf":1.0},"86":{"tf":1.0}}}}},"p":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":4,"docs":{"40":{"tf":1.4142135623730951},"49":{"tf":1.0},"61":{"tf":1.0},"76":{"tf":1.4142135623730951}}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":2,"docs":{"49":{"tf":1.0},"72":{"tf":1.7320508075688772}}}},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"49":{"tf":1.0}}}}},"l":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":4,"docs":{"11":{"tf":1.0},"18":{"tf":1.0},"61":{"tf":1.0},"74":{"tf":1.0}}}}},"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"18":{"tf":1.0}}}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"22":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"14":{"tf":1.0}}}}}}},"r":{"df":0,"docs":{},"t":{"df":2,"docs":{"74":{"tf":1.0},"79":{"tf":1.4142135623730951}}}},"s":{"df":3,"docs":{"12":{"tf":1.0},"19":{"tf":1.0},"73":{"tf":1.0}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"61":{"tf":1.7320508075688772}}}}}}},"t":{"c":{"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":1,"docs":{"45":{"tf":1.0}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":1,"docs":{"18":{"tf":1.4142135623730951}}}}}}}},"f":{"a":{"c":{"df":0,"docs":{},"e":{"df":1,"docs":{"5":{"tf":1.0}}},"t":{"df":3,"docs":{"18":{"tf":1.0},"62":{"tf":1.0},"72":{"tf":1.0}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"18":{"tf":1.4142135623730951}}}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":3,"docs":{"18":{"tf":1.4142135623730951},"62":{"tf":1.0},"86":{"tf":1.0}}}},"l":{"df":0,"docs":{},"l":{"df":2,"docs":{"40":{"tf":1.0},"72":{"tf":1.0}}}},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"40":{"tf":1.0}}}}}},"q":{"df":1,"docs":{"81":{"tf":1.0}}},"r":{"df":2,"docs":{"49":{"tf":1.0},"72":{"tf":1.0}}},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"49":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"4":{"tf":1.0},"72":{"tf":1.0}}}}}}},"df":1,"docs":{"54":{"tf":1.0}},"e":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"63":{"tf":1.0}}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":6,"docs":{"18":{"tf":1.0},"4":{"tf":1.0},"74":{"tf":1.0},"83":{"tf":1.0},"85":{"tf":1.0},"89":{"tf":1.0}}}}}},"df":0,"docs":{},"w":{"df":4,"docs":{"11":{"tf":1.0},"24":{"tf":1.0},"37":{"tf":1.0},"61":{"tf":1.0}}}},"i":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":5,"docs":{"16":{"tf":1.0},"17":{"tf":1.0},"54":{"tf":1.0},"59":{"tf":1.4142135623730951},"64":{"tf":1.0}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"52":{"tf":1.0}}}}}},"n":{"a":{"df":0,"docs":{},"l":{"df":3,"docs":{"64":{"tf":1.0},"76":{"tf":1.0},"79":{"tf":1.4142135623730951}}}},"d":{"df":3,"docs":{"1":{"tf":1.0},"7":{"tf":1.0},"85":{"tf":1.0}}},"df":0,"docs":{},"e":{"df":6,"docs":{"0":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"52":{"tf":1.0},"58":{"tf":1.0},"65":{"tf":1.0}}},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"df":1,"docs":{"54":{"tf":1.4142135623730951}}}},"t":{"df":1,"docs":{"14":{"tf":1.0}}}}},"r":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"89":{"tf":1.0}}}}},"x":{"df":5,"docs":{"0":{"tf":1.4142135623730951},"37":{"tf":1.4142135623730951},"60":{"tf":1.0},"62":{"tf":1.0},"74":{"tf":1.0}}}},"l":{"a":{"df":0,"docs":{},"g":{"df":3,"docs":{"18":{"tf":1.0},"54":{"tf":2.0},"67":{"tf":1.0}}},"w":{"df":1,"docs":{"72":{"tf":1.4142135623730951}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"p":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{".":{"df":0,"docs":{},"p":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{"df":1,"docs":{"54":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}}}}}}},"o":{"c":{"df":0,"docs":{},"u":{"df":1,"docs":{"89":{"tf":1.0}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":13,"docs":{"10":{"tf":1.0},"12":{"tf":1.0},"33":{"tf":1.0},"49":{"tf":1.0},"6":{"tf":1.0},"61":{"tf":1.0},"62":{"tf":1.0},"64":{"tf":1.4142135623730951},"65":{"tf":1.0},"7":{"tf":1.0},"75":{"tf":1.0},"76":{"tf":1.0},"77":{"tf":1.0}}}}}},"r":{"c":{"df":1,"docs":{"60":{"tf":1.0}}},"df":0,"docs":{},"k":{"df":2,"docs":{"21":{"tf":1.7320508075688772},"23":{"tf":1.0}}},"m":{"a":{"df":0,"docs":{},"t":{"df":3,"docs":{"18":{"tf":1.0},"76":{"tf":1.0},"77":{"tf":1.0}},"t":{"df":1,"docs":{"61":{"tf":1.0}}}}},"df":0,"docs":{}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"e":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"62":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"u":{"df":0,"docs":{},"m":{"df":1,"docs":{"22":{"tf":1.0}}}}},"u":{"df":0,"docs":{},"n":{"d":{"df":5,"docs":{"18":{"tf":1.0},"3":{"tf":1.0},"59":{"tf":1.0},"71":{"tf":1.0},"72":{"tf":1.0}},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"21":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}}}},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"72":{"tf":1.0}}}}}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":1,"docs":{"54":{"tf":1.4142135623730951}},"w":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"k":{"df":1,"docs":{"63":{"tf":1.0}}}}}}}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"d":{"df":5,"docs":{"5":{"tf":1.0},"6":{"tf":1.0},"63":{"tf":1.0},"78":{"tf":1.0},"79":{"tf":1.0}}},"df":0,"docs":{}}}}}}},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":4,"docs":{"60":{"tf":1.0},"61":{"tf":1.0},"65":{"tf":1.4142135623730951},"71":{"tf":1.0}}}}},"n":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":6,"docs":{"36":{"tf":1.7320508075688772},"37":{"tf":1.0},"48":{"tf":1.4142135623730951},"61":{"tf":1.4142135623730951},"68":{"tf":1.0},"89":{"tf":1.0}}}}}}},"d":{"df":1,"docs":{"62":{"tf":1.0}}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":3,"docs":{"76":{"tf":1.0},"77":{"tf":1.0},"86":{"tf":1.0}},"m":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":2,"docs":{"68":{"tf":1.0},"69":{"tf":1.0}}}}}}}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"40":{"tf":1.0}}}},"u":{"df":0,"docs":{},"r":{"df":3,"docs":{"18":{"tf":1.0},"62":{"tf":1.0},"86":{"tf":1.0}}}}}}},"g":{"a":{"df":8,"docs":{"0":{"tf":1.7320508075688772},"13":{"tf":1.0},"14":{"tf":1.4142135623730951},"34":{"tf":1.7320508075688772},"37":{"tf":1.0},"40":{"tf":1.4142135623730951},"67":{"tf":1.0},"69":{"tf":1.0}},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"72":{"tf":1.0}}}},"s":{"_":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":0,"docs":{},"u":{"df":0,"docs":{},"m":{"df":1,"docs":{"54":{"tf":2.449489742783178}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"v":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"88":{"tf":1.0}}}}}},"df":2,"docs":{"17":{"tf":1.0},"26":{"tf":1.0}},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":15,"docs":{"17":{"tf":1.0},"2":{"tf":1.0},"37":{"tf":1.0},"49":{"tf":1.0},"5":{"tf":1.0},"58":{"tf":1.0},"6":{"tf":1.0},"61":{"tf":1.0},"62":{"tf":2.0},"63":{"tf":1.0},"65":{"tf":1.0},"66":{"tf":1.4142135623730951},"72":{"tf":1.0},"74":{"tf":1.0},"85":{"tf":1.0}}}}},"t":{"df":4,"docs":{"1":{"tf":1.0},"49":{"tf":1.0},"55":{"tf":1.0},"57":{"tf":1.0}}}},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"74":{"tf":1.0}},"h":{"df":0,"docs":{},"u":{"b":{"df":1,"docs":{"60":{"tf":1.0}}},"df":0,"docs":{}}}},"v":{"df":0,"docs":{},"e":{"df":1,"docs":{"89":{"tf":1.0}},"n":{"df":3,"docs":{"62":{"tf":1.0},"65":{"tf":1.0},"89":{"tf":1.0}}}}}},"l":{"a":{"d":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"56":{"tf":1.0}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"o":{"d":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{".":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":1,"docs":{"22":{"tf":1.0}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":2,"docs":{"74":{"tf":1.4142135623730951},"76":{"tf":1.4142135623730951}},"e":{"df":1,"docs":{"74":{"tf":1.0}}},"o":{"d":{"df":2,"docs":{"58":{"tf":1.0},"63":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"r":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"52":{"tf":1.0}}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"49":{"tf":1.0}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"58":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"w":{"df":1,"docs":{"14":{"tf":1.0}}}}},"u":{"a":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":1,"docs":{"72":{"tf":1.0}}}}}},"df":0,"docs":{}}},"df":0,"docs":{},"i":{"d":{"df":6,"docs":{"1":{"tf":1.4142135623730951},"4":{"tf":1.0},"55":{"tf":1.0},"56":{"tf":1.0},"61":{"tf":1.0},"75":{"tf":1.0}}},"df":0,"docs":{}}}},"h":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"f":{"df":1,"docs":{"72":{"tf":1.0}}},"l":{"df":0,"docs":{},"u":{"c":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"62":{"tf":1.0}}}}},"df":0,"docs":{}}}},"n":{"d":{"df":1,"docs":{"72":{"tf":1.0}},"i":{"df":1,"docs":{"50":{"tf":1.0}}}},"df":0,"docs":{}},"p":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":2,"docs":{"18":{"tf":1.4142135623730951},"64":{"tf":1.0}}}}}},"r":{"d":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"21":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"w":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"72":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"s":{"df":0,"docs":{},"h":{"df":7,"docs":{"0":{"tf":1.0},"18":{"tf":1.0},"35":{"tf":1.0},"40":{"tf":2.0},"41":{"tf":1.0},"42":{"tf":1.0},"65":{"tf":1.0}},"m":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"65":{"tf":1.0}}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"e":{"a":{"d":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{},"p":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"z":{"df":1,"docs":{"14":{"tf":1.0}}}}}},"df":5,"docs":{"0":{"tf":1.0},"14":{"tf":2.449489742783178},"27":{"tf":1.4142135623730951},"37":{"tf":1.0},"67":{"tf":2.0}}},"v":{"df":0,"docs":{},"i":{"df":1,"docs":{"63":{"tf":1.0}}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":1,"docs":{"0":{"tf":1.0}}}},"p":{"df":4,"docs":{"1":{"tf":1.0},"11":{"tf":1.7320508075688772},"51":{"tf":1.4142135623730951},"55":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"76":{"tf":1.0}}}}}},"n":{"c":{"df":1,"docs":{"67":{"tf":1.0}}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"e":{"df":4,"docs":{"48":{"tf":1.0},"62":{"tf":1.0},"71":{"tf":1.0},"85":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":4,"docs":{"4":{"tf":1.0},"63":{"tf":1.0},"76":{"tf":1.0},"88":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":3,"docs":{"31":{"tf":1.0},"61":{"tf":1.0},"75":{"tf":1.0}}}}}}}}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"66":{"tf":1.0}}}}}}},"o":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":1,"docs":{"62":{"tf":1.0}}}},"o":{"d":{"df":1,"docs":{"64":{"tf":1.0}}},"df":0,"docs":{}},"s":{"df":0,"docs":{},"t":{"df":2,"docs":{"73":{"tf":1.4142135623730951},"79":{"tf":1.0}}}}},"t":{"df":0,"docs":{},"t":{"df":0,"docs":{},"p":{"df":0,"docs":{},"s":{":":{"/":{"/":{"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"u":{"b":{".":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"/":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"u":{"df":0,"docs":{},"m":{"/":{"df":0,"docs":{},"g":{"df":0,"docs":{},"o":{"df":1,"docs":{"74":{"tf":1.0}}}}},"df":0,"docs":{}}}}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"u":{"b":{"df":1,"docs":{"73":{"tf":1.0}}},"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"n":{"df":1,"docs":{"62":{"tf":1.0}}}},"df":0,"docs":{}}}},"i":{".":{"df":1,"docs":{"18":{"tf":1.4142135623730951}}},"d":{"df":1,"docs":{"23":{"tf":1.4142135623730951}},"e":{"a":{"df":1,"docs":{"49":{"tf":1.0}},"l":{"df":1,"docs":{"72":{"tf":1.0}}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":2,"docs":{"65":{"tf":1.0},"77":{"tf":1.0}}}}}}}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"n":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":3,"docs":{"0":{"tf":1.0},"38":{"tf":1.0},"72":{"tf":1.4142135623730951}}}}}},"m":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":12,"docs":{"0":{"tf":1.4142135623730951},"4":{"tf":1.0},"49":{"tf":2.449489742783178},"59":{"tf":1.0},"6":{"tf":1.0},"66":{"tf":2.23606797749979},"69":{"tf":1.0},"72":{"tf":1.0},"74":{"tf":1.7320508075688772},"75":{"tf":1.0},"76":{"tf":1.7320508075688772},"77":{"tf":1.4142135623730951}}}}}}},"i":{"df":2,"docs":{"18":{"tf":1.0},"37":{"tf":1.0}}}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":3,"docs":{"1":{"tf":1.0},"61":{"tf":1.0},"62":{"tf":1.0}}}}},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"v":{"df":2,"docs":{"85":{"tf":1.0},"89":{"tf":1.0}}}}}}},"n":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":2,"docs":{"13":{"tf":1.0},"14":{"tf":1.0}}}}}}},"l":{"df":0,"docs":{},"u":{"d":{"df":7,"docs":{"13":{"tf":1.0},"14":{"tf":1.0},"16":{"tf":1.0},"4":{"tf":1.0},"49":{"tf":1.0},"52":{"tf":1.0},"59":{"tf":1.0}}},"df":0,"docs":{}}},"o":{"df":0,"docs":{},"m":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"18":{"tf":1.0}}}}}}}},"r":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"s":{"df":3,"docs":{"13":{"tf":1.7320508075688772},"14":{"tf":1.0},"86":{"tf":1.0}}}},"df":0,"docs":{}}}},"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"73":{"tf":1.0}}}}}}}},"u":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":2,"docs":{"49":{"tf":1.0},"72":{"tf":1.0}}}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"i":{"df":2,"docs":{"49":{"tf":1.0},"72":{"tf":1.0}}}},"df":0,"docs":{}}}}},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"14":{"tf":1.0}}}}}},"o":{"df":1,"docs":{"17":{"tf":1.0}},"r":{"df":0,"docs":{},"m":{"df":3,"docs":{"17":{"tf":1.0},"2":{"tf":1.0},"26":{"tf":1.0}}}}},"r":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"u":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"5":{"tf":1.0}}}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"49":{"tf":1.0},"62":{"tf":1.0}},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"48":{"tf":1.0}}}}}}},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":3,"docs":{"30":{"tf":1.0},"48":{"tf":1.4142135623730951},"73":{"tf":1.0}}}}},"k":{"df":0,"docs":{},"w":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":1,"docs":{"68":{"tf":1.0}}}}}},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":4,"docs":{"18":{"tf":2.23606797749979},"4":{"tf":1.0},"61":{"tf":1.0},"83":{"tf":1.4142135623730951}}}}},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"u":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"d":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"d":{"df":1,"docs":{"48":{"tf":1.7320508075688772}}},"df":0,"docs":{}}}}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}},"t":{"df":0,"docs":{},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"48":{"tf":1.7320508075688772}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}},"p":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"18":{"tf":1.0}}}}}},"df":3,"docs":{"18":{"tf":1.4142135623730951},"22":{"tf":1.0},"24":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"i":{"d":{"df":5,"docs":{"18":{"tf":1.0},"40":{"tf":1.0},"51":{"tf":1.0},"67":{"tf":1.0},"77":{"tf":1.0}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":1,"docs":{"52":{"tf":1.0}}}}}},"t":{"a":{"df":0,"docs":{},"l":{"df":7,"docs":{"51":{"tf":2.23606797749979},"58":{"tf":1.0},"6":{"tf":1.4142135623730951},"7":{"tf":1.0},"74":{"tf":1.0},"79":{"tf":1.4142135623730951},"8":{"tf":1.4142135623730951}}},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":4,"docs":{"0":{"tf":1.0},"40":{"tf":1.0},"53":{"tf":1.4142135623730951},"76":{"tf":1.7320508075688772}}}}}},"df":0,"docs":{},"e":{"a":{"d":{"df":10,"docs":{"0":{"tf":1.4142135623730951},"14":{"tf":1.0},"18":{"tf":1.0},"32":{"tf":1.4142135623730951},"35":{"tf":1.0},"40":{"tf":1.4142135623730951},"50":{"tf":1.0},"61":{"tf":1.0},"65":{"tf":1.0},"76":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"u":{"c":{"df":0,"docs":{},"t":{"df":7,"docs":{"10":{"tf":1.0},"18":{"tf":1.0},"32":{"tf":1.0},"40":{"tf":1.0},"52":{"tf":1.0},"72":{"tf":1.0},"8":{"tf":1.0}}}},"df":0,"docs":{}}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"g":{"df":0,"docs":{},"r":{"df":4,"docs":{"20":{"tf":1.4142135623730951},"49":{"tf":1.0},"74":{"tf":1.7320508075688772},"76":{"tf":2.0}}}},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"73":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"f":{"a":{"c":{"df":5,"docs":{"24":{"tf":1.4142135623730951},"49":{"tf":1.0},"66":{"tf":1.0},"68":{"tf":1.7320508075688772},"73":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"m":{"df":0,"docs":{},"e":{"d":{"df":0,"docs":{},"i":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"16":{"tf":1.0}}}}},"df":2,"docs":{"63":{"tf":1.0},"64":{"tf":1.0}}}},"df":0,"docs":{}}},"n":{"df":4,"docs":{"48":{"tf":1.4142135623730951},"55":{"tf":1.0},"63":{"tf":1.0},"65":{"tf":1.0}}},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"72":{"tf":1.4142135623730951}}}}}}}},"r":{"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"u":{"c":{"df":3,"docs":{"0":{"tf":1.4142135623730951},"1":{"tf":1.0},"49":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"u":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"61":{"tf":1.0}}}}}},"v":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"d":{"df":1,"docs":{"65":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"v":{"df":2,"docs":{"18":{"tf":1.0},"62":{"tf":1.4142135623730951}}}}}}},"r":{"df":7,"docs":{"16":{"tf":1.4142135623730951},"47":{"tf":1.7320508075688772},"48":{"tf":1.0},"63":{"tf":1.4142135623730951},"64":{"tf":1.4142135623730951},"66":{"tf":1.0},"69":{"tf":1.0}}},"s":{"a":{"df":1,"docs":{"72":{"tf":1.0}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"’":{"df":0,"docs":{},"t":{"df":4,"docs":{"0":{"tf":1.0},"18":{"tf":1.0},"72":{"tf":1.0},"75":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"u":{"df":1,"docs":{"60":{"tf":1.0}}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":1,"docs":{"61":{"tf":1.0}}},"r":{"df":1,"docs":{"65":{"tf":1.0}}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"f":{"df":4,"docs":{"49":{"tf":1.0},"5":{"tf":1.0},"60":{"tf":1.0},"68":{"tf":1.0}}}}}},"’":{"d":{"df":1,"docs":{"48":{"tf":1.0}}},"df":6,"docs":{"18":{"tf":1.0},"19":{"tf":1.0},"49":{"tf":1.0},"50":{"tf":1.0},"52":{"tf":1.0},"87":{"tf":1.0}}}}},"j":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":2,"docs":{"4":{"tf":1.0},"72":{"tf":2.23606797749979}}}},"s":{"df":1,"docs":{"19":{"tf":1.0}},"o":{"df":0,"docs":{},"n":{"df":2,"docs":{"18":{"tf":1.4142135623730951},"24":{"tf":1.4142135623730951}}}}},"u":{"d":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"62":{"tf":1.0}}}}}}}}},"df":0,"docs":{}}},"k":{"b":{"df":1,"docs":{"54":{"tf":1.0}}},"df":0,"docs":{},"e":{"c":{"c":{"a":{"df":0,"docs":{},"k":{"2":{"5":{"6":{"df":1,"docs":{"35":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{},"e":{"df":0,"docs":{},"p":{"df":5,"docs":{"11":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"62":{"tf":1.0},"88":{"tf":1.0}}}},"p":{"df":0,"docs":{},"t":{"df":2,"docs":{"58":{"tf":1.0},"67":{"tf":1.0}}}},"y":{"df":1,"docs":{"76":{"tf":1.0}},"w":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"40":{"tf":1.0}}},"df":0,"docs":{}}}}}},"n":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":3,"docs":{"11":{"tf":1.0},"18":{"tf":1.0},"49":{"tf":1.0}},"l":{"df":0,"docs":{},"e":{"d":{"df":0,"docs":{},"g":{"df":1,"docs":{"69":{"tf":1.0}}}},"df":0,"docs":{}}},"n":{"df":1,"docs":{"18":{"tf":1.0}}}}}}},"l":{"a":{"c":{"df":0,"docs":{},"k":{"df":2,"docs":{"14":{"tf":1.0},"69":{"tf":1.0}}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"u":{"a":{"df":0,"docs":{},"g":{"df":4,"docs":{"22":{"tf":1.0},"49":{"tf":2.6457513110645907},"61":{"tf":1.0},"88":{"tf":1.0}}}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"g":{"df":2,"docs":{"62":{"tf":1.0},"77":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"37":{"tf":1.0},"86":{"tf":1.0}}}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"85":{"tf":1.7320508075688772}}}}}},"u":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"h":{"df":1,"docs":{"73":{"tf":1.0}}}},"df":0,"docs":{}}},"y":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"69":{"tf":1.0}}}},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"37":{"tf":1.0}}}}}}},"df":0,"docs":{},"e":{"a":{"d":{"df":4,"docs":{"0":{"tf":1.0},"36":{"tf":1.0},"37":{"tf":1.0},"62":{"tf":1.0}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":1,"docs":{"58":{"tf":1.0}}}},"v":{"df":1,"docs":{"68":{"tf":1.0}}}},"df":1,"docs":{"69":{"tf":1.0}},"g":{"a":{"c":{"df":0,"docs":{},"i":{"df":1,"docs":{"48":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"72":{"tf":1.0}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":8,"docs":{"12":{"tf":2.0},"36":{"tf":1.0},"37":{"tf":1.0},"4":{"tf":1.0},"49":{"tf":1.7320508075688772},"52":{"tf":1.0},"63":{"tf":1.0},"76":{"tf":1.0}}}}},"x":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"66":{"tf":1.0}}}}}},"i":{"b":{"c":{"df":1,"docs":{"80":{"tf":1.0}}},"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":9,"docs":{"18":{"tf":3.4641016151377544},"49":{"tf":2.0},"5":{"tf":1.0},"59":{"tf":1.0},"64":{"tf":1.0},"65":{"tf":1.0},"66":{"tf":1.7320508075688772},"73":{"tf":1.0},"76":{"tf":1.7320508075688772}}}}},"df":0,"docs":{}}},"df":2,"docs":{"62":{"tf":1.0},"88":{"tf":1.0}},"f":{"df":0,"docs":{},"t":{"df":1,"docs":{"63":{"tf":1.0}}}},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":3,"docs":{"34":{"tf":1.0},"37":{"tf":1.0},"86":{"tf":1.0}}}}},"n":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"r":{"df":3,"docs":{"37":{"tf":1.0},"67":{"tf":1.0},"72":{"tf":1.0}}}},"df":3,"docs":{"19":{"tf":1.0},"30":{"tf":1.0},"61":{"tf":1.0}}},"k":{"a":{"df":0,"docs":{},"g":{"df":1,"docs":{"18":{"tf":1.0}}}},"df":5,"docs":{"18":{"tf":3.605551275463989},"49":{"tf":1.0},"64":{"tf":1.0},"65":{"tf":1.4142135623730951},"78":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":4,"docs":{"18":{"tf":1.4142135623730951},"64":{"tf":1.0},"68":{"tf":1.0},"71":{"tf":1.0}}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"61":{"tf":1.0}}}}},"u":{"df":0,"docs":{},"x":{"df":2,"docs":{"7":{"tf":1.0},"78":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"36":{"tf":1.0}}}},"t":{"df":0,"docs":{},"t":{"df":0,"docs":{},"l":{"df":1,"docs":{"59":{"tf":1.0}}}}},"v":{"df":0,"docs":{},"e":{"df":3,"docs":{"32":{"tf":1.0},"59":{"tf":1.0},"72":{"tf":1.0}}}}},"l":{"d":{"df":3,"docs":{"64":{"tf":1.0},"68":{"tf":1.4142135623730951},"79":{"tf":1.0}}},"df":1,"docs":{"66":{"tf":1.0}},"m":{"df":1,"docs":{"62":{"tf":1.0}}},"v":{"df":0,"docs":{},"m":{"/":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":0,"docs":{},"s":{"c":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"/":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"79":{"tf":1.0}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}}}},"g":{"df":0,"docs":{},"n":{"df":0,"docs":{},"u":{"/":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"79":{"tf":1.0}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"y":{"df":0,"docs":{},"s":{"_":{"1":{"8":{"1":{"_":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"x":{"=":{"$":{"df":0,"docs":{},"{":{"df":0,"docs":{},"p":{"df":0,"docs":{},"w":{"d":{"df":0,"docs":{},"}":{"/":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"79":{"tf":1.0}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":13,"docs":{"12":{"tf":1.4142135623730951},"16":{"tf":1.0},"29":{"tf":1.0},"30":{"tf":1.0},"49":{"tf":1.0},"5":{"tf":1.0},"63":{"tf":1.4142135623730951},"64":{"tf":1.4142135623730951},"66":{"tf":2.449489742783178},"68":{"tf":2.449489742783178},"69":{"tf":1.4142135623730951},"79":{"tf":3.0},"89":{"tf":1.0}}}}},"o":{"c":{"a":{"df":0,"docs":{},"l":{"df":4,"docs":{"13":{"tf":1.0},"50":{"tf":1.0},"58":{"tf":1.0},"60":{"tf":1.0}}},"t":{"df":1,"docs":{"59":{"tf":1.0}}}},"df":0,"docs":{},"k":{"df":1,"docs":{"59":{"tf":1.4142135623730951}}}},"df":0,"docs":{},"g":{"df":1,"docs":{"52":{"tf":2.23606797749979}},"i":{"c":{"df":4,"docs":{"49":{"tf":1.0},"66":{"tf":1.4142135623730951},"74":{"tf":1.0},"76":{"tf":1.0}}},"df":0,"docs":{}}},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"23":{"tf":1.0}}}}}},"o":{"df":0,"docs":{},"k":{"df":1,"docs":{"88":{"tf":1.0}}}},"s":{"df":0,"docs":{},"e":{"df":1,"docs":{"72":{"tf":1.0}}},"s":{"df":1,"docs":{"62":{"tf":1.0}}}},"t":{"df":2,"docs":{"76":{"tf":1.0},"77":{"tf":1.0}}},"w":{"df":5,"docs":{"36":{"tf":1.0},"37":{"tf":1.0},"49":{"tf":1.0},"52":{"tf":1.0},"88":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":4,"docs":{"49":{"tf":1.4142135623730951},"63":{"tf":1.0},"64":{"tf":1.4142135623730951},"66":{"tf":1.0}}}}}}},"m":{"a":{"c":{"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":2,"docs":{"13":{"tf":1.0},"69":{"tf":1.4142135623730951}}}}},"o":{"df":1,"docs":{"7":{"tf":1.0}}},"r":{"df":0,"docs":{},"o":{"df":1,"docs":{"61":{"tf":1.4142135623730951}}}}},"d":{"df":0,"docs":{},"e":{"df":1,"docs":{"60":{"tf":1.0}}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"61":{"tf":1.0}}},"df":0,"docs":{}},"n":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"d":{"df":1,"docs":{"72":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}}}},"i":{"df":0,"docs":{},"n":{"df":4,"docs":{"60":{"tf":1.0},"66":{"tf":1.0},"72":{"tf":1.0},"89":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":3,"docs":{"18":{"tf":1.0},"30":{"tf":1.0},"63":{"tf":1.0}}}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"m":{"df":1,"docs":{"49":{"tf":1.0}}}},"df":0,"docs":{}}}}},"t":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":7,"docs":{"23":{"tf":1.0},"57":{"tf":1.0},"60":{"tf":1.0},"62":{"tf":1.7320508075688772},"63":{"tf":1.0},"65":{"tf":1.0},"68":{"tf":1.0}}}}},"df":0,"docs":{}}}},"j":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":2,"docs":{"7":{"tf":1.0},"89":{"tf":1.4142135623730951}}}}},"k":{"df":0,"docs":{},"e":{"df":13,"docs":{"18":{"tf":1.4142135623730951},"19":{"tf":1.0},"3":{"tf":1.0},"40":{"tf":1.0},"49":{"tf":1.0},"51":{"tf":1.0},"58":{"tf":1.0},"60":{"tf":1.0},"61":{"tf":1.0},"65":{"tf":1.0},"67":{"tf":1.0},"74":{"tf":1.0},"79":{"tf":1.7320508075688772}},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"58":{"tf":1.4142135623730951}}}}}}},"n":{"a":{"df":0,"docs":{},"g":{"df":1,"docs":{"74":{"tf":1.0}}}},"df":0,"docs":{},"i":{"df":2,"docs":{"36":{"tf":1.0},"5":{"tf":1.4142135623730951}},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":1,"docs":{"88":{"tf":1.0}}}}}}}},"u":{"a":{"df":0,"docs":{},"l":{"df":2,"docs":{"40":{"tf":1.0},"76":{"tf":1.0}}}},"df":0,"docs":{}}},"p":{"df":1,"docs":{"72":{"tf":1.0}}},"t":{"c":{"df":0,"docs":{},"h":{"df":1,"docs":{"76":{"tf":1.0}}}},"df":0,"docs":{}},"x":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"u":{"df":0,"docs":{},"m":{"df":1,"docs":{"37":{"tf":1.0}}}}}}},"y":{"b":{"df":1,"docs":{"49":{"tf":1.0}}},"df":0,"docs":{}}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":1,"docs":{"37":{"tf":1.0}}}}}},"d":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"k":{"df":1,"docs":{"3":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"n":{"df":2,"docs":{"37":{"tf":1.0},"61":{"tf":1.0}},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":1,"docs":{"61":{"tf":1.7320508075688772}}}}}},"s":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"65":{"tf":1.0}}}}}},"c":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"df":1,"docs":{"18":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":7,"docs":{"13":{"tf":1.7320508075688772},"14":{"tf":2.449489742783178},"27":{"tf":1.0},"36":{"tf":1.7320508075688772},"37":{"tf":2.8284271247461903},"54":{"tf":1.0},"67":{"tf":1.7320508075688772}}}}}},"r":{"df":0,"docs":{},"g":{"df":1,"docs":{"60":{"tf":1.0}}}},"s":{"df":0,"docs":{},"s":{"a":{"df":0,"docs":{},"g":{"df":2,"docs":{"11":{"tf":1.0},"61":{"tf":1.0}}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":3,"docs":{"0":{"tf":1.0},"14":{"tf":1.0},"67":{"tf":1.0}}}}}},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"c":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":1,"docs":{"62":{"tf":1.0}}}}},"df":0,"docs":{}}}},"s":{"df":0,"docs":{},"s":{"df":2,"docs":{"18":{"tf":1.4142135623730951},"69":{"tf":1.4142135623730951}}},"t":{"a":{"df":0,"docs":{},"k":{"df":1,"docs":{"62":{"tf":1.0}}}},"df":0,"docs":{}}},"x":{"df":1,"docs":{"49":{"tf":1.0}}}},"l":{"df":0,"docs":{},"o":{"a":{"d":{"df":1,"docs":{"37":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}},"o":{"d":{"df":0,"docs":{},"e":{"df":2,"docs":{"18":{"tf":1.4142135623730951},"47":{"tf":1.0}},"l":{"df":5,"docs":{"0":{"tf":1.0},"40":{"tf":1.4142135623730951},"46":{"tf":1.4142135623730951},"49":{"tf":1.0},"62":{"tf":1.0}}}},"u":{"df":0,"docs":{},"l":{"df":2,"docs":{"61":{"tf":1.0},"9":{"tf":1.0}}}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"69":{"tf":1.0}}}}}},"r":{"df":0,"docs":{},"e":{"df":9,"docs":{"11":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"2":{"tf":1.0},"5":{"tf":1.7320508075688772},"50":{"tf":1.0},"52":{"tf":1.0},"72":{"tf":1.4142135623730951},"77":{"tf":1.7320508075688772}}}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":3,"docs":{"24":{"tf":1.0},"72":{"tf":1.0},"89":{"tf":1.0}}}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":1,"docs":{"88":{"tf":1.0}}}}},"v":{"df":0,"docs":{},"e":{"df":1,"docs":{"72":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"z":{"df":0,"docs":{},"e":{"df":1,"docs":{"37":{"tf":1.4142135623730951}}}}},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":1,"docs":{"37":{"tf":1.0}}}}}}},"u":{"c":{"df":0,"docs":{},"h":{"df":4,"docs":{"4":{"tf":1.0},"50":{"tf":1.0},"72":{"tf":1.0},"77":{"tf":1.4142135623730951}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":2,"docs":{"49":{"tf":1.0},"5":{"tf":1.0}}}}}}},"s":{"df":0,"docs":{},"l":{"df":4,"docs":{"68":{"tf":1.0},"7":{"tf":1.0},"78":{"tf":1.0},"80":{"tf":1.7320508075688772}}}}}},"n":{"a":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":3,"docs":{"5":{"tf":1.4142135623730951},"59":{"tf":1.0},"61":{"tf":1.0}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":2,"docs":{"4":{"tf":1.0},"72":{"tf":1.4142135623730951}}}},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"49":{"tf":1.0}}}}}},"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"88":{"tf":1.0}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"e":{"d":{"df":8,"docs":{"18":{"tf":1.7320508075688772},"36":{"tf":1.0},"49":{"tf":1.0},"59":{"tf":1.4142135623730951},"61":{"tf":1.0},"68":{"tf":1.0},"72":{"tf":1.0},"88":{"tf":1.0}}},"df":0,"docs":{}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"18":{"tf":1.0},"76":{"tf":1.0}}}}},"w":{"df":3,"docs":{"40":{"tf":1.0},"59":{"tf":1.0},"74":{"tf":1.0}}}},"i":{"c":{"df":0,"docs":{},"e":{"df":1,"docs":{"19":{"tf":1.0}}}},"df":0,"docs":{}},"o":{"d":{"df":0,"docs":{},"e":{".":{"df":0,"docs":{},"j":{"df":3,"docs":{"19":{"tf":1.0},"78":{"tf":1.0},"9":{"tf":1.0}}}},"df":2,"docs":{"50":{"tf":1.4142135623730951},"77":{"tf":1.0}}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"5":{"tf":1.0}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"n":{"df":6,"docs":{"18":{"tf":1.0},"59":{"tf":1.0},"61":{"tf":1.0},"65":{"tf":1.0},"67":{"tf":1.0},"68":{"tf":1.0}}},"t":{"a":{"b":{"df":0,"docs":{},"l":{"df":2,"docs":{"0":{"tf":1.0},"88":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"e":{"df":7,"docs":{"18":{"tf":1.4142135623730951},"19":{"tf":1.0},"36":{"tf":1.0},"49":{"tf":1.0},"71":{"tf":1.0},"72":{"tf":1.0},"76":{"tf":1.0}},"w":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"df":1,"docs":{"36":{"tf":1.0}}}}}}}}}}},"p":{"df":0,"docs":{},"m":{"df":2,"docs":{"19":{"tf":1.7320508075688772},"9":{"tf":1.0}}},"x":{"df":1,"docs":{"19":{"tf":1.0}}}},"u":{"a":{"df":0,"docs":{},"n":{"c":{"df":2,"docs":{"62":{"tf":1.0},"77":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"72":{"tf":1.0}}}}}}},"m":{"b":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"61":{"tf":1.0},"72":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"27":{"tf":1.4142135623730951}}}}},"t":{"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":2,"docs":{"40":{"tf":1.0},"50":{"tf":1.0}}}}}}}}},"o":{"(":{"df":0,"docs":{},"n":{"df":1,"docs":{"72":{"tf":1.0}}}},"b":{"df":0,"docs":{},"j":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":7,"docs":{"16":{"tf":1.0},"18":{"tf":1.0},"25":{"tf":1.0},"27":{"tf":1.0},"28":{"tf":1.4142135623730951},"64":{"tf":1.4142135623730951},"71":{"tf":1.0}}}},"df":0,"docs":{}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":4,"docs":{"0":{"tf":1.0},"3":{"tf":1.0},"31":{"tf":1.0},"76":{"tf":1.4142135623730951}}}}}},"t":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":2,"docs":{"78":{"tf":1.0},"79":{"tf":1.0}}}}},"df":0,"docs":{}},"v":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":1,"docs":{"61":{"tf":1.0}}}}}}},"df":3,"docs":{"12":{"tf":1.0},"19":{"tf":1.0},"29":{"tf":1.0}},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":3,"docs":{"4":{"tf":1.0},"46":{"tf":1.0},"67":{"tf":1.0}}}},"i":{"c":{"df":0,"docs":{},"i":{"df":3,"docs":{"18":{"tf":1.0},"61":{"tf":1.0},"65":{"tf":1.0}}}},"df":0,"docs":{}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":4,"docs":{"36":{"tf":1.4142135623730951},"37":{"tf":1.0},"38":{"tf":1.0},"54":{"tf":1.0}}}}}}},"k":{"(":{"0":{"df":1,"docs":{"54":{"tf":1.4142135623730951}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":1,"docs":{"54":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}}}}}}}}},"df":0,"docs":{}}}}},"df":1,"docs":{"54":{"tf":1.4142135623730951}}},"n":{"df":4,"docs":{"15":{"tf":1.0},"62":{"tf":1.0},"72":{"tf":1.0},"88":{"tf":1.0}},"w":{"a":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"82":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"p":{"c":{"df":0,"docs":{},"o":{"d":{"df":3,"docs":{"40":{"tf":1.0},"46":{"tf":1.0},"84":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":2,"docs":{"56":{"tf":1.0},"60":{"tf":1.0}}},"r":{"df":3,"docs":{"37":{"tf":1.0},"65":{"tf":1.0},"7":{"tf":1.0}}}},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":1,"docs":{"69":{"tf":1.4142135623730951}}}}}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":12,"docs":{"12":{"tf":3.3166247903554},"16":{"tf":1.0},"18":{"tf":1.7320508075688772},"28":{"tf":1.0},"29":{"tf":1.0},"37":{"tf":1.0},"4":{"tf":1.0},"49":{"tf":1.0},"64":{"tf":1.0},"67":{"tf":1.0},"69":{"tf":2.23606797749979},"89":{"tf":1.4142135623730951}},"i":{"df":0,"docs":{},"z":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"63":{"tf":1.0}}}}}}},"o":{"df":0,"docs":{},"n":{"df":2,"docs":{"11":{"tf":1.4142135623730951},"19":{"tf":1.4142135623730951}}}}}}},"r":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"48":{"tf":1.0},"72":{"tf":1.4142135623730951}}}}},"df":0,"docs":{},"g":{"a":{"df":0,"docs":{},"n":{"df":1,"docs":{"59":{"tf":1.0}}}},"df":0,"docs":{}},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"o":{"df":0,"docs":{},"g":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"69":{"tf":1.0}}}}}}}}},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"w":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":1,"docs":{"18":{"tf":1.0}}}}}}}}},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":2,"docs":{"31":{"tf":1.0},"36":{"tf":1.0}}}}},"t":{"_":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"54":{"tf":1.0}}}}}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"df":1,"docs":{"76":{"tf":1.4142135623730951}}}}},"d":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"23":{"tf":1.0}}}},"df":0,"docs":{}},"df":1,"docs":{"85":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"61":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"f":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"37":{"tf":1.0}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"g":{"a":{"df":1,"docs":{"36":{"tf":1.0}}},"df":0,"docs":{}}}},"p":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":3,"docs":{"16":{"tf":1.0},"17":{"tf":1.0},"52":{"tf":1.0}}}}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"r":{"c":{"df":0,"docs":{},"h":{"df":2,"docs":{"5":{"tf":1.0},"64":{"tf":1.0}}}},"df":0,"docs":{}}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"df":1,"docs":{"72":{"tf":1.0}}}}},"df":2,"docs":{"65":{"tf":1.0},"88":{"tf":1.0}},"f":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":1,"docs":{"67":{"tf":1.0}}}}}},"h":{"df":0,"docs":{},"e":{"a":{"d":{"df":1,"docs":{"72":{"tf":1.7320508075688772}}},"df":0,"docs":{}},"df":0,"docs":{}}},"r":{"df":0,"docs":{},"i":{"d":{"df":1,"docs":{"48":{"tf":1.0}}},"df":0,"docs":{}}},"v":{"df":0,"docs":{},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"df":1,"docs":{"89":{"tf":1.0}}}}}}}}},"z":{"df":1,"docs":{"12":{"tf":1.0}}}},"p":{"a":{"c":{"df":0,"docs":{},"k":{"a":{"df":0,"docs":{},"g":{"df":3,"docs":{"19":{"tf":1.7320508075688772},"74":{"tf":1.0},"9":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"r":{"df":1,"docs":{"77":{"tf":1.0}}}},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":12,"docs":{"0":{"tf":1.7320508075688772},"31":{"tf":1.0},"34":{"tf":1.0},"38":{"tf":1.0},"43":{"tf":1.0},"50":{"tf":1.0},"52":{"tf":1.0},"70":{"tf":1.4142135623730951},"72":{"tf":1.0},"73":{"tf":1.7320508075688772},"76":{"tf":1.4142135623730951},"77":{"tf":1.0}}}}}},"n":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"61":{"tf":1.0}}},"df":0,"docs":{}}},"r":{"a":{"c":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"88":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"61":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"21":{"tf":1.4142135623730951}}},"y":{"/":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"c":{"@":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"19":{"tf":1.0}}}}}}},"df":0,"docs":{}}},"df":1,"docs":{"19":{"tf":1.0}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"5":{"tf":1.0},"66":{"tf":1.4142135623730951}}}}},"t":{"df":1,"docs":{"59":{"tf":1.0}},"i":{"df":2,"docs":{"20":{"tf":1.0},"61":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"s":{"df":2,"docs":{"60":{"tf":1.4142135623730951},"72":{"tf":1.0}}}},"t":{"df":0,"docs":{},"h":{"=":{"/":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"/":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"/":{"df":0,"docs":{},"g":{"df":0,"docs":{},"o":{"df":1,"docs":{"74":{"tf":1.0}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":3,"docs":{"15":{"tf":1.4142135623730951},"61":{"tf":1.0},"74":{"tf":1.0}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":1,"docs":{"49":{"tf":1.0}}}}}}}},"c":{"df":1,"docs":{"45":{"tf":1.0}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"m":{"df":3,"docs":{"12":{"tf":1.0},"63":{"tf":1.0},"85":{"tf":1.0}}}}}}}},"h":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"df":1,"docs":{"75":{"tf":1.0}}}}}}}}}}},"i":{"df":0,"docs":{},"e":{"c":{"df":1,"docs":{"49":{"tf":1.0}}},"df":0,"docs":{}},"n":{"df":1,"docs":{"59":{"tf":1.0}}},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":3,"docs":{"47":{"tf":1.0},"58":{"tf":1.0},"89":{"tf":1.0}}}}}}}},"l":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"m":{"df":4,"docs":{"65":{"tf":1.0},"68":{"tf":1.0},"7":{"tf":1.0},"88":{"tf":1.0}}}}}}}},"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"s":{"df":8,"docs":{"10":{"tf":1.0},"11":{"tf":1.0},"58":{"tf":1.0},"59":{"tf":1.7320508075688772},"61":{"tf":1.4142135623730951},"62":{"tf":1.0},"7":{"tf":1.0},"8":{"tf":1.0}}}},"df":0,"docs":{}}},"o":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"36":{"tf":1.4142135623730951},"40":{"tf":1.4142135623730951}}}}}}},"l":{"a":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{"df":1,"docs":{"4":{"tf":1.0}}}}},"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"i":{"df":1,"docs":{"62":{"tf":1.0}}}},"df":0,"docs":{}},"k":{"a":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":6,"docs":{"2":{"tf":1.4142135623730951},"4":{"tf":1.0},"46":{"tf":1.0},"49":{"tf":1.0},"70":{"tf":1.0},"73":{"tf":1.0}}}}},"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{"df":7,"docs":{"1":{"tf":1.0},"5":{"tf":1.0},"52":{"tf":1.0},"6":{"tf":1.4142135623730951},"64":{"tf":1.4142135623730951},"70":{"tf":1.0},"79":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}}},"p":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"r":{"df":2,"docs":{"18":{"tf":1.0},"63":{"tf":1.0}}}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"t":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"19":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"62":{"tf":1.0}}}}}}},"s":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"b":{"df":0,"docs":{},"l":{"df":5,"docs":{"13":{"tf":1.0},"14":{"tf":1.0},"59":{"tf":1.4142135623730951},"75":{"tf":1.7320508075688772},"88":{"tf":1.0}}}},"df":0,"docs":{}}},"t":{"df":1,"docs":{"22":{"tf":1.0}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":3,"docs":{"0":{"tf":1.0},"31":{"tf":1.0},"65":{"tf":1.0}}}}}}},"w":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"63":{"tf":1.0},"77":{"tf":1.0}}}}}},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"c":{"df":2,"docs":{"49":{"tf":1.0},"72":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":3,"docs":{"59":{"tf":1.4142135623730951},"60":{"tf":1.7320508075688772},"62":{"tf":1.0}},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"59":{"tf":1.0}}}},"i":{"df":0,"docs":{},"x":{"df":1,"docs":{"59":{"tf":1.4142135623730951}}}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":2,"docs":{"37":{"tf":1.0},"75":{"tf":1.0}}}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":2,"docs":{"65":{"tf":1.0},"67":{"tf":1.0}}}}},"r":{"a":{"df":0,"docs":{},"n":{"d":{"a":{"df":0,"docs":{},"o":{"df":1,"docs":{"44":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"49":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"r":{"df":3,"docs":{"18":{"tf":1.0},"62":{"tf":1.0},"72":{"tf":1.0}},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"89":{"tf":1.0}}}}}}}},"o":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"62":{"tf":1.4142135623730951}}}},"df":1,"docs":{"72":{"tf":1.0}}}}}},"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":6,"docs":{"47":{"tf":1.0},"62":{"tf":1.0},"63":{"tf":1.0},"64":{"tf":1.0},"68":{"tf":1.0},"8":{"tf":1.0}}}}}},"d":{"df":0,"docs":{},"u":{"c":{"df":5,"docs":{"18":{"tf":1.0},"45":{"tf":1.0},"46":{"tf":1.0},"62":{"tf":1.0},"63":{"tf":1.0}},"t":{"df":1,"docs":{"18":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"85":{"tf":1.0}}}}},"g":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"m":{"df":2,"docs":{"49":{"tf":1.0},"88":{"tf":1.0}}}},"df":0,"docs":{}}},"j":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":6,"docs":{"3":{"tf":1.0},"5":{"tf":1.0},"56":{"tf":1.0},"62":{"tf":1.4142135623730951},"79":{"tf":1.0},"88":{"tf":1.0}},"’":{"df":2,"docs":{"57":{"tf":1.0},"89":{"tf":1.0}}}}},"df":0,"docs":{}}},"o":{"df":0,"docs":{},"f":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"z":{"df":1,"docs":{"54":{"tf":2.449489742783178}}}}}},"df":2,"docs":{"49":{"tf":1.0},"62":{"tf":1.0}}}},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"65":{"tf":1.0}}}}}}},"v":{"df":0,"docs":{},"e":{"df":1,"docs":{"76":{"tf":1.0}}},"i":{"d":{"df":8,"docs":{"18":{"tf":2.23606797749979},"49":{"tf":1.0},"53":{"tf":1.0},"61":{"tf":1.7320508075688772},"63":{"tf":1.0},"73":{"tf":1.0},"76":{"tf":1.4142135623730951},"88":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"x":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"72":{"tf":1.0}}}}}}},"u":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"c":{"df":2,"docs":{"48":{"tf":1.4142135623730951},"61":{"tf":1.0}}},"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"df":1,"docs":{"19":{"tf":1.0}}}}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":1,"docs":{"60":{"tf":1.4142135623730951}}}},"r":{"df":0,"docs":{},"g":{"a":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"=":{"6":{"1":{"4":{"4":{"/":{"3":{"1":{"4":{"5":{"7":{"2":{"8":{"df":1,"docs":{"54":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"s":{"df":5,"docs":{"16":{"tf":1.0},"17":{"tf":1.0},"30":{"tf":1.0},"49":{"tf":1.0},"72":{"tf":1.0}}}}}},"s":{"df":0,"docs":{},"h":{"df":1,"docs":{"60":{"tf":1.0}}}}},"v":{"df":0,"docs":{},"m":{"df":24,"docs":{"0":{"tf":1.4142135623730951},"13":{"tf":1.0},"14":{"tf":1.4142135623730951},"16":{"tf":1.0},"18":{"tf":1.0},"24":{"tf":1.0},"25":{"tf":1.0},"27":{"tf":1.0},"28":{"tf":1.0},"32":{"tf":1.0},"36":{"tf":1.0},"4":{"tf":1.4142135623730951},"45":{"tf":1.0},"49":{"tf":1.0},"52":{"tf":1.0},"67":{"tf":1.0},"68":{"tf":1.0},"69":{"tf":1.0},"70":{"tf":1.4142135623730951},"71":{"tf":1.0},"72":{"tf":2.6457513110645907},"76":{"tf":1.4142135623730951},"88":{"tf":1.0},"89":{"tf":1.0}}}},"y":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"49":{"tf":1.0}}}}}}}},"q":{"df":0,"docs":{},"u":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"61":{"tf":1.0}}}},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"56":{"tf":1.0}}}}}}},"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"k":{"df":1,"docs":{"57":{"tf":1.0}}}},"df":0,"docs":{}}}},"r":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":1,"docs":{"18":{"tf":1.4142135623730951}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"62":{"tf":1.0}}}},"df":0,"docs":{}}}}},"w":{"df":1,"docs":{"18":{"tf":1.0}}}},"df":0,"docs":{},"e":{"a":{"d":{"a":{"b":{"df":0,"docs":{},"l":{"df":2,"docs":{"58":{"tf":1.0},"61":{"tf":1.0}}}},"df":0,"docs":{}},"df":5,"docs":{"1":{"tf":1.0},"31":{"tf":1.0},"37":{"tf":1.0},"58":{"tf":1.0},"62":{"tf":1.0}},"m":{"df":0,"docs":{},"e":{".":{"df":0,"docs":{},"m":{"d":{"df":2,"docs":{"10":{"tf":1.0},"57":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"z":{"df":2,"docs":{"69":{"tf":1.0},"88":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":6,"docs":{"18":{"tf":1.0},"40":{"tf":1.0},"49":{"tf":1.0},"66":{"tf":1.0},"67":{"tf":1.0},"88":{"tf":1.0}}}}}},"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":1,"docs":{"36":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"m":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"d":{"df":2,"docs":{"66":{"tf":1.0},"85":{"tf":1.0}}},"df":0,"docs":{}}}}}}},"d":{"df":0,"docs":{},"u":{"c":{"df":1,"docs":{"72":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"f":{"_":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"54":{"tf":2.449489742783178}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":7,"docs":{"36":{"tf":1.0},"4":{"tf":1.0},"57":{"tf":1.0},"6":{"tf":1.0},"75":{"tf":1.0},"76":{"tf":1.0},"8":{"tf":1.0}}}}},"g":{"a":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"47":{"tf":1.0}},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"18":{"tf":1.0}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":2,"docs":{"13":{"tf":1.0},"72":{"tf":1.4142135623730951}}}}},"u":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"49":{"tf":1.0}}}},"df":0,"docs":{}},"r":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"62":{"tf":1.0}}}}}},"df":0,"docs":{}}}},"j":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"62":{"tf":1.0}}}},"df":0,"docs":{}}},"l":{"a":{"df":0,"docs":{},"t":{"df":3,"docs":{"24":{"tf":1.0},"37":{"tf":1.0},"46":{"tf":1.4142135623730951}}}},"df":1,"docs":{"18":{"tf":1.0}},"e":{"a":{"df":0,"docs":{},"s":{"df":4,"docs":{"65":{"tf":1.4142135623730951},"68":{"tf":1.4142135623730951},"7":{"tf":1.4142135623730951},"89":{"tf":1.7320508075688772}}}},"df":0,"docs":{}},"i":{"df":2,"docs":{"63":{"tf":1.0},"89":{"tf":1.0}}},"o":{"c":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"71":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"x":{".":{"df":0,"docs":{},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"k":{"a":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{".":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":1,"docs":{"23":{"tf":1.0}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":1,"docs":{"23":{"tf":1.4142135623730951}}}},"o":{"df":0,"docs":{},"v":{"df":3,"docs":{"46":{"tf":1.0},"72":{"tf":1.0},"76":{"tf":1.0}}}}},"p":{"df":0,"docs":{},"l":{"a":{"c":{"df":1,"docs":{"87":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":1,"docs":{"77":{"tf":1.0}}}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":2,"docs":{"51":{"tf":1.0},"60":{"tf":1.0}}}}}}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":1,"docs":{"49":{"tf":1.0}},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":2,"docs":{"63":{"tf":1.0},"64":{"tf":1.0}}}}}}},"o":{"d":{"df":0,"docs":{},"u":{"c":{"df":1,"docs":{"65":{"tf":1.7320508075688772}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"q":{"df":0,"docs":{},"u":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":2,"docs":{"18":{"tf":1.0},"60":{"tf":1.7320508075688772}}}}},"i":{"df":0,"docs":{},"r":{"df":11,"docs":{"18":{"tf":1.0},"50":{"tf":1.0},"51":{"tf":1.0},"6":{"tf":1.0},"61":{"tf":1.0},"62":{"tf":1.0},"68":{"tf":1.0},"71":{"tf":1.0},"72":{"tf":1.0},"74":{"tf":1.0},"79":{"tf":1.0}}}}}},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"c":{".":{"df":0,"docs":{},"j":{"df":1,"docs":{"78":{"tf":1.0}}}},"df":26,"docs":{"10":{"tf":1.0},"11":{"tf":1.7320508075688772},"12":{"tf":1.0},"18":{"tf":2.0},"19":{"tf":1.0},"20":{"tf":1.0},"21":{"tf":1.0},"22":{"tf":1.0},"23":{"tf":1.4142135623730951},"26":{"tf":1.0},"27":{"tf":1.4142135623730951},"29":{"tf":1.0},"4":{"tf":2.0},"47":{"tf":1.0},"5":{"tf":2.0},"58":{"tf":1.4142135623730951},"6":{"tf":1.0},"64":{"tf":1.7320508075688772},"65":{"tf":1.4142135623730951},"68":{"tf":1.0},"7":{"tf":1.4142135623730951},"79":{"tf":1.0},"8":{"tf":1.0},"85":{"tf":1.0},"87":{"tf":1.4142135623730951},"89":{"tf":1.0}}},"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"18":{"tf":1.0}}}},"v":{"df":1,"docs":{"18":{"tf":1.0}}}},"u":{"df":0,"docs":{},"r":{"c":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}}}},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"t":{"df":3,"docs":{"38":{"tf":1.0},"43":{"tf":1.0},"86":{"tf":1.0}}}},"df":0,"docs":{}}}},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":2,"docs":{"66":{"tf":1.0},"76":{"tf":1.7320508075688772}}}}}},"t":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"88":{"tf":1.0}}}}},"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"d":{"a":{"df":0,"docs":{},"t":{"a":{"df":1,"docs":{"43":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":7,"docs":{"32":{"tf":1.0},"35":{"tf":1.0},"38":{"tf":1.0},"41":{"tf":1.0},"42":{"tf":1.0},"43":{"tf":1.0},"48":{"tf":2.449489742783178}}}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":4,"docs":{"13":{"tf":1.0},"14":{"tf":1.0},"43":{"tf":1.0},"54":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"df":1,"docs":{"62":{"tf":1.0}}}},"v":{"df":37,"docs":{"0":{"tf":1.7320508075688772},"10":{"tf":1.0},"24":{"tf":1.0},"3":{"tf":1.0},"31":{"tf":1.0},"34":{"tf":1.0},"37":{"tf":1.0},"38":{"tf":1.0},"40":{"tf":2.23606797749979},"43":{"tf":1.0},"47":{"tf":1.0},"49":{"tf":1.0},"5":{"tf":2.0},"50":{"tf":1.7320508075688772},"51":{"tf":1.7320508075688772},"52":{"tf":1.4142135623730951},"53":{"tf":1.0},"54":{"tf":1.0},"55":{"tf":1.0},"56":{"tf":1.0},"59":{"tf":1.4142135623730951},"6":{"tf":1.0},"62":{"tf":1.0},"63":{"tf":1.4142135623730951},"64":{"tf":1.0},"65":{"tf":1.0},"66":{"tf":2.23606797749979},"68":{"tf":1.0},"70":{"tf":1.7320508075688772},"72":{"tf":1.0},"73":{"tf":2.23606797749979},"74":{"tf":1.0},"76":{"tf":2.8284271247461903},"77":{"tf":1.7320508075688772},"79":{"tf":1.7320508075688772},"88":{"tf":1.4142135623730951},"9":{"tf":1.4142135623730951}},"e":{"_":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{"_":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"x":{"=":{"$":{"df":0,"docs":{},"{":{"df":0,"docs":{},"p":{"df":0,"docs":{},"w":{"d":{"df":0,"docs":{},"}":{"/":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"79":{"tf":1.0}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":1,"docs":{"79":{"tf":1.0}}}}}}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"88":{"tf":1.0}}}}}}},"w":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"88":{"tf":1.0}}}}}}},"i":{"df":0,"docs":{},"s":{"c":{"df":5,"docs":{"49":{"tf":1.0},"63":{"tf":1.0},"64":{"tf":1.0},"69":{"tf":1.0},"72":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"o":{"a":{"d":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"p":{"df":3,"docs":{"49":{"tf":1.0},"88":{"tf":1.0},"89":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":0,"docs":{},"p":{"df":1,"docs":{"46":{"tf":1.4142135623730951}}}}}},"o":{"df":0,"docs":{},"m":{"df":1,"docs":{"76":{"tf":1.0}}},"t":{"df":1,"docs":{"51":{"tf":1.0}}}},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":1,"docs":{"89":{"tf":1.0}}}}}},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":4,"docs":{"0":{"tf":1.0},"34":{"tf":1.4142135623730951},"58":{"tf":1.0},"60":{"tf":1.0}}}},"n":{"df":10,"docs":{"0":{"tf":1.0},"3":{"tf":1.0},"48":{"tf":1.0},"50":{"tf":1.4142135623730951},"53":{"tf":1.0},"58":{"tf":1.4142135623730951},"59":{"tf":1.0},"74":{"tf":1.0},"78":{"tf":1.0},"85":{"tf":1.0}},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":6,"docs":{"50":{"tf":1.4142135623730951},"51":{"tf":1.4142135623730951},"53":{"tf":1.0},"54":{"tf":1.0},"76":{"tf":2.449489742783178},"77":{"tf":1.4142135623730951}}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":12,"docs":{"0":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"32":{"tf":2.0},"37":{"tf":1.0},"40":{"tf":1.4142135623730951},"50":{"tf":1.0},"52":{"tf":1.4142135623730951},"70":{"tf":1.0},"73":{"tf":1.7320508075688772},"76":{"tf":1.0},"77":{"tf":1.0}},"e":{":":{":":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":1,"docs":{"54":{"tf":1.7320508075688772}},"i":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{":":{":":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"c":{"df":1,"docs":{"54":{"tf":2.449489742783178}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"s":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"g":{"=":{"df":0,"docs":{},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"k":{"a":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{"=":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"c":{"df":1,"docs":{"52":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}},"r":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"=":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"c":{"df":2,"docs":{"52":{"tf":1.0},"54":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}}}},"df":1,"docs":{"52":{"tf":1.0}}}}}},"df":7,"docs":{"49":{"tf":2.8284271247461903},"51":{"tf":1.0},"59":{"tf":1.7320508075688772},"61":{"tf":1.0},"68":{"tf":1.0},"80":{"tf":1.4142135623730951},"88":{"tf":1.0}}}}},"v":{"6":{"4":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"a":{"c":{"b":{"df":1,"docs":{"68":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"s":{"a":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":2,"docs":{"49":{"tf":1.0},"89":{"tf":1.0}}}},"m":{"df":0,"docs":{},"e":{"df":7,"docs":{"18":{"tf":1.4142135623730951},"49":{"tf":1.0},"61":{"tf":1.0},"65":{"tf":1.0},"72":{"tf":1.0},"77":{"tf":1.0},"84":{"tf":1.0}}}},"n":{"d":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"x":{"df":3,"docs":{"50":{"tf":1.0},"72":{"tf":1.0},"76":{"tf":1.0}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"v":{"df":0,"docs":{},"e":{"df":1,"docs":{"40":{"tf":1.0}}}}},"c":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":1,"docs":{"88":{"tf":1.4142135623730951}}}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":3,"docs":{"49":{"tf":1.0},"68":{"tf":1.0},"79":{"tf":1.0}}}}}}},"d":{"df":0,"docs":{},"k":{"df":1,"docs":{"49":{"tf":1.4142135623730951}}}},"df":1,"docs":{"12":{"tf":1.0}},"e":{"a":{"df":0,"docs":{},"l":{"_":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"(":{"df":0,"docs":{},"f":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"g":{"df":1,"docs":{"54":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}},"m":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"49":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"40":{"tf":1.0}}}}}}}}}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"89":{"tf":1.0}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":2,"docs":{"0":{"tf":1.0},"31":{"tf":1.4142135623730951}}}}}},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"62":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"d":{"df":1,"docs":{"72":{"tf":1.0}}},"df":8,"docs":{"11":{"tf":1.0},"22":{"tf":1.0},"37":{"tf":1.0},"49":{"tf":1.0},"51":{"tf":1.0},"66":{"tf":1.0},"83":{"tf":1.0},"84":{"tf":1.0}}},"m":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":5,"docs":{"0":{"tf":1.0},"61":{"tf":1.0},"69":{"tf":1.0},"75":{"tf":1.0},"76":{"tf":1.0}}}}},"df":0,"docs":{}},"n":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"62":{"tf":1.0}}}}},"t":{"df":1,"docs":{"77":{"tf":1.0}}}},"t":{"df":8,"docs":{"12":{"tf":1.0},"18":{"tf":1.0},"25":{"tf":1.0},"27":{"tf":1.0},"28":{"tf":1.0},"29":{"tf":1.0},"67":{"tf":1.0},"76":{"tf":1.4142135623730951}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"s":{".":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"u":{"df":1,"docs":{"30":{"tf":1.0}}}}}},"df":0,"docs":{}}}}},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"28":{"tf":1.4142135623730951}},"i":{"df":0,"docs":{},"z":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{".":{"df":0,"docs":{},"m":{"df":0,"docs":{},"o":{"d":{"df":1,"docs":{"29":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}}}}},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"k":{"a":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{".":{"d":{"df":0,"docs":{},"e":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"m":{"df":1,"docs":{"26":{"tf":1.0}}}}}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"y":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":1,"docs":{"27":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"f":{"df":0,"docs":{},"g":{".":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"s":{"df":1,"docs":{"27":{"tf":1.0}}}}},"df":0,"docs":{}}},"s":{"df":0,"docs":{},"t":{"a":{"c":{"df":0,"docs":{},"k":{"df":0,"docs":{},"s":{"df":1,"docs":{"27":{"tf":1.0}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}}}}}},"df":1,"docs":{"25":{"tf":1.0}}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}}}}}},"h":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":1,"docs":{"64":{"tf":1.4142135623730951}}}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":1,"docs":{"72":{"tf":1.0}}}},"w":{"df":2,"docs":{"62":{"tf":1.0},"72":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"n":{"df":1,"docs":{"62":{"tf":1.0}},"i":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"c":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":2,"docs":{"88":{"tf":1.0},"89":{"tf":1.0}}}}}}},"df":2,"docs":{"69":{"tf":1.0},"88":{"tf":1.0}}},"df":0,"docs":{}}}}}},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"r":{"df":3,"docs":{"18":{"tf":1.0},"67":{"tf":1.0},"72":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"87":{"tf":1.0}}}}}},"df":0,"docs":{}}},"p":{"df":0,"docs":{},"l":{"df":4,"docs":{"18":{"tf":1.0},"66":{"tf":1.0},"74":{"tf":1.0},"76":{"tf":1.0}},"i":{"df":1,"docs":{"76":{"tf":1.0}},"f":{"df":0,"docs":{},"i":{"df":2,"docs":{"18":{"tf":1.0},"76":{"tf":1.0}}}}}}}},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"l":{"df":6,"docs":{"29":{"tf":1.0},"32":{"tf":1.0},"5":{"tf":1.4142135623730951},"50":{"tf":1.0},"72":{"tf":1.0},"88":{"tf":1.0}}}}},"t":{"df":1,"docs":{"72":{"tf":1.0}}},"z":{"df":0,"docs":{},"e":{"df":15,"docs":{"0":{"tf":1.4142135623730951},"12":{"tf":1.7320508075688772},"13":{"tf":2.449489742783178},"14":{"tf":2.449489742783178},"27":{"tf":2.0},"32":{"tf":1.4142135623730951},"36":{"tf":1.7320508075688772},"37":{"tf":1.0},"38":{"tf":1.0},"40":{"tf":1.0},"42":{"tf":1.0},"43":{"tf":1.0},"67":{"tf":1.4142135623730951},"86":{"tf":1.4142135623730951},"89":{"tf":1.0}}}}},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":1,"docs":{"62":{"tf":1.4142135623730951}}},"w":{"df":1,"docs":{"72":{"tf":1.7320508075688772}},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"72":{"tf":1.0}}}}}}},"m":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":4,"docs":{"13":{"tf":1.0},"14":{"tf":1.0},"47":{"tf":1.0},"49":{"tf":1.0}}}},"r":{"df":0,"docs":{},"t":{"df":3,"docs":{"4":{"tf":1.0},"63":{"tf":1.0},"72":{"tf":1.0}}}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"f":{"df":0,"docs":{},"t":{"df":0,"docs":{},"w":{"a":{"df":0,"docs":{},"r":{"df":3,"docs":{"49":{"tf":1.0},"56":{"tf":1.0},"62":{"tf":1.0}}}},"df":0,"docs":{}}}},"l":{"c":{"df":18,"docs":{"11":{"tf":1.0},"15":{"tf":2.0},"18":{"tf":2.23606797749979},"24":{"tf":1.0},"36":{"tf":1.0},"47":{"tf":1.7320508075688772},"6":{"tf":1.0},"63":{"tf":1.4142135623730951},"64":{"tf":1.0},"65":{"tf":1.4142135623730951},"69":{"tf":1.4142135623730951},"75":{"tf":1.0},"76":{"tf":1.0},"8":{"tf":1.4142135623730951},"82":{"tf":1.0},"85":{"tf":1.0},"87":{"tf":1.4142135623730951},"89":{"tf":1.0}}},"df":0,"docs":{},"e":{"df":1,"docs":{"62":{"tf":1.0}}},"i":{"d":{"df":25,"docs":{"0":{"tf":1.4142135623730951},"1":{"tf":1.4142135623730951},"18":{"tf":2.23606797749979},"21":{"tf":1.4142135623730951},"22":{"tf":1.0},"3":{"tf":1.0},"31":{"tf":1.4142135623730951},"33":{"tf":1.4142135623730951},"36":{"tf":1.0},"4":{"tf":2.0},"40":{"tf":1.0},"49":{"tf":1.7320508075688772},"5":{"tf":1.0},"57":{"tf":1.0},"6":{"tf":1.7320508075688772},"62":{"tf":1.0},"63":{"tf":1.7320508075688772},"64":{"tf":1.4142135623730951},"75":{"tf":1.7320508075688772},"76":{"tf":1.7320508075688772},"8":{"tf":1.0},"82":{"tf":1.0},"85":{"tf":1.0},"88":{"tf":2.0},"89":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"49":{"tf":1.0}}}}},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"49":{"tf":1.0}}},"i":{"df":0,"docs":{},"m":{"df":3,"docs":{"50":{"tf":1.0},"52":{"tf":1.0},"59":{"tf":1.0}}}}},"w":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"72":{"tf":1.0}}}}}}}},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"62":{"tf":1.0}}}}}}},"r":{"c":{"df":9,"docs":{"10":{"tf":1.0},"17":{"tf":1.0},"18":{"tf":1.0},"51":{"tf":1.0},"56":{"tf":1.0},"64":{"tf":1.4142135623730951},"74":{"tf":1.0},"79":{"tf":1.0},"89":{"tf":1.0}}},"df":0,"docs":{}}}},"p":{"a":{"c":{"df":0,"docs":{},"e":{"df":1,"docs":{"13":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"df":0,"docs":{},"e":{"c":{"df":2,"docs":{"76":{"tf":1.4142135623730951},"77":{"tf":1.4142135623730951}},"i":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"68":{"tf":1.0}}}},"df":0,"docs":{},"f":{"df":8,"docs":{"25":{"tf":1.0},"27":{"tf":1.0},"28":{"tf":1.0},"49":{"tf":1.0},"68":{"tf":1.0},"69":{"tf":1.0},"72":{"tf":1.0},"76":{"tf":1.4142135623730951}},"i":{"df":3,"docs":{"15":{"tf":1.0},"16":{"tf":1.0},"30":{"tf":1.0}}}}}},"df":0,"docs":{},"e":{"d":{"df":3,"docs":{"1":{"tf":1.0},"72":{"tf":1.4142135623730951},"88":{"tf":1.0}}},"df":0,"docs":{}}}},"r":{"c":{"/":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"/":{"b":{"a":{"df":0,"docs":{},"r":{".":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{":":{"b":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"18":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":1,"docs":{"18":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"t":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"73":{"tf":1.0}}}},"c":{"df":0,"docs":{},"k":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"z":{"df":1,"docs":{"13":{"tf":1.0}}}}}},"df":6,"docs":{"0":{"tf":1.0},"13":{"tf":2.6457513110645907},"27":{"tf":1.4142135623730951},"69":{"tf":1.0},"75":{"tf":1.0},"76":{"tf":1.0}}}},"df":0,"docs":{},"n":{"d":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"76":{"tf":1.0}}}}},"r":{"d":{"df":4,"docs":{"24":{"tf":1.4142135623730951},"52":{"tf":1.0},"59":{"tf":1.0},"65":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"_":{"df":0,"docs":{},"i":{"d":{"df":1,"docs":{"48":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}}},"df":4,"docs":{"55":{"tf":1.0},"57":{"tf":1.0},"69":{"tf":1.0},"82":{"tf":1.0}},"u":{"df":0,"docs":{},"p":{"df":3,"docs":{"13":{"tf":1.0},"14":{"tf":1.0},"72":{"tf":1.0}}}}}},"t":{"df":0,"docs":{},"e":{"df":5,"docs":{"48":{"tf":1.4142135623730951},"53":{"tf":1.0},"65":{"tf":1.0},"72":{"tf":1.0},"76":{"tf":1.4142135623730951}}},"i":{"c":{"df":4,"docs":{"14":{"tf":1.0},"65":{"tf":1.0},"67":{"tf":1.4142135623730951},"78":{"tf":1.0}}},"df":0,"docs":{}}}},"d":{"df":1,"docs":{"18":{"tf":1.4142135623730951}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"p":{"df":2,"docs":{"64":{"tf":1.0},"76":{"tf":1.0}}}},"i":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":1,"docs":{"18":{"tf":1.0}}}}},"o":{"c":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"62":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"g":{"df":1,"docs":{"76":{"tf":1.0}}}},"df":0,"docs":{}}},"r":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":1,"docs":{"62":{"tf":1.0}},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"w":{"a":{"df":0,"docs":{},"r":{"d":{"df":2,"docs":{"7":{"tf":1.0},"80":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"df":2,"docs":{"74":{"tf":1.4142135623730951},"77":{"tf":1.4142135623730951}}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"49":{"tf":1.0}}}}}}},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":2,"docs":{"18":{"tf":1.0},"61":{"tf":1.0}}}},"p":{"df":1,"docs":{"50":{"tf":1.0}}}},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":3,"docs":{"34":{"tf":1.0},"40":{"tf":1.0},"66":{"tf":1.0}}}}}}},"u":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"18":{"tf":1.0}}}}}},"df":0,"docs":{}}},"u":{"d":{"df":0,"docs":{},"i":{"df":1,"docs":{"0":{"tf":1.0}}}},"df":0,"docs":{}},"y":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":2,"docs":{"61":{"tf":1.0},"62":{"tf":1.0}}}}}},"u":{"b":{"df":0,"docs":{},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":2,"docs":{"60":{"tf":1.4142135623730951},"62":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"18":{"tf":1.0}}}}}}}}},"c":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"20":{"tf":1.0}},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"72":{"tf":1.0}}}}}}}},"df":0,"docs":{},"h":{"df":2,"docs":{"49":{"tf":1.0},"61":{"tf":1.0}}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"i":{"df":2,"docs":{"18":{"tf":1.0},"62":{"tf":1.0}}}},"df":0,"docs":{}}}},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"77":{"tf":1.0}}}},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"46":{"tf":1.0}}}}}}},"p":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":4,"docs":{"18":{"tf":1.0},"34":{"tf":1.0},"36":{"tf":1.0},"40":{"tf":1.4142135623730951}}}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":15,"docs":{"18":{"tf":1.0},"21":{"tf":1.0},"23":{"tf":1.0},"28":{"tf":1.0},"37":{"tf":1.0},"39":{"tf":1.0},"4":{"tf":1.0},"49":{"tf":1.4142135623730951},"65":{"tf":1.0},"7":{"tf":1.0},"79":{"tf":1.4142135623730951},"82":{"tf":1.7320508075688772},"83":{"tf":1.4142135623730951},"84":{"tf":1.0},"85":{"tf":1.7320508075688772}}}},"s":{"df":2,"docs":{"18":{"tf":1.0},"54":{"tf":1.0}}}}}},"r":{"df":0,"docs":{},"e":{"df":1,"docs":{"18":{"tf":1.0}}}}},"w":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"77":{"tf":1.0}}}},"df":0,"docs":{}},"y":{"df":1,"docs":{"68":{"tf":1.0}},"m":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":2,"docs":{"18":{"tf":1.4142135623730951},"61":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}},"s":{"c":{"a":{"df":0,"docs":{},"l":{"df":2,"docs":{"54":{"tf":1.0},"73":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":1,"docs":{"7":{"tf":1.0}}}}}}}},"t":{"a":{"df":0,"docs":{},"k":{"df":0,"docs":{},"e":{"df":3,"docs":{"18":{"tf":1.0},"63":{"tf":1.0},"77":{"tf":1.0}}}},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":12,"docs":{"1":{"tf":1.0},"4":{"tf":1.0},"65":{"tf":1.0},"68":{"tf":1.4142135623730951},"69":{"tf":1.7320508075688772},"70":{"tf":1.4142135623730951},"71":{"tf":1.4142135623730951},"72":{"tf":1.0},"73":{"tf":1.0},"75":{"tf":1.0},"78":{"tf":1.0},"79":{"tf":2.23606797749979}}}}}}},"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"h":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"49":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"m":{"df":1,"docs":{"63":{"tf":1.0}},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"g":{"df":1,"docs":{"32":{"tf":1.0}}}}}}}}}},"s":{"df":0,"docs":{},"t":{"df":7,"docs":{"48":{"tf":1.4142135623730951},"58":{"tf":1.4142135623730951},"60":{"tf":1.0},"74":{"tf":2.6457513110645907},"76":{"tf":3.4641016151377544},"77":{"tf":3.0},"79":{"tf":1.0}}}}},"h":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"k":{"df":2,"docs":{"4":{"tf":1.0},"77":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":2,"docs":{"32":{"tf":1.0},"37":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"59":{"tf":1.0}}}},"’":{"df":1,"docs":{"0":{"tf":1.0}}}}}},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":5,"docs":{"11":{"tf":1.0},"18":{"tf":1.0},"5":{"tf":1.0},"59":{"tf":1.0},"61":{"tf":1.4142135623730951}}}},"r":{"d":{"df":2,"docs":{"20":{"tf":1.0},"61":{"tf":1.0}}},"df":0,"docs":{}}},"o":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":2,"docs":{"11":{"tf":1.0},"18":{"tf":1.0}}}},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":1,"docs":{"69":{"tf":1.0}}}}}},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":2,"docs":{"64":{"tf":1.0},"76":{"tf":1.0}}}}}}},"u":{"df":5,"docs":{"18":{"tf":1.0},"37":{"tf":1.0},"40":{"tf":1.0},"69":{"tf":1.0},"77":{"tf":1.0}},"m":{"b":{"df":1,"docs":{"58":{"tf":1.0}}},"df":0,"docs":{}}}},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"49":{"tf":1.0}}}}}}},"m":{"df":0,"docs":{},"e":{"df":7,"docs":{"12":{"tf":1.7320508075688772},"18":{"tf":2.8284271247461903},"38":{"tf":1.0},"43":{"tf":1.0},"45":{"tf":1.0},"46":{"tf":1.0},"72":{"tf":1.4142135623730951}},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"89":{"tf":1.0}}}}}}},"n":{"df":0,"docs":{},"i":{"df":1,"docs":{"77":{"tf":1.0}}}},"p":{"df":3,"docs":{"11":{"tf":1.0},"32":{"tf":1.0},"74":{"tf":1.0}}}},"m":{"df":0,"docs":{},"p":{"/":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"19":{"tf":1.0}}}}}},"df":0,"docs":{}}},"o":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":2,"docs":{"59":{"tf":1.0},"74":{"tf":1.0}}}}}},"o":{"df":0,"docs":{},"l":{"df":7,"docs":{"18":{"tf":1.0},"20":{"tf":1.4142135623730951},"49":{"tf":1.0},"62":{"tf":1.0},"74":{"tf":1.0},"76":{"tf":1.4142135623730951},"86":{"tf":1.0}},"k":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"21":{"tf":1.4142135623730951}}}}}}},"t":{"a":{"df":0,"docs":{},"l":{"df":2,"docs":{"13":{"tf":1.4142135623730951},"14":{"tf":1.0}}}},"df":0,"docs":{}}},"r":{"a":{"c":{"df":0,"docs":{},"e":{"df":2,"docs":{"52":{"tf":2.0},"54":{"tf":3.0}}}},"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"13":{"tf":1.0}},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"49":{"tf":1.0}}}}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"66":{"tf":1.0}}}},"n":{"df":0,"docs":{},"s":{"a":{"c":{"df":0,"docs":{},"t":{"df":2,"docs":{"40":{"tf":1.0},"77":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"t":{"df":7,"docs":{"31":{"tf":1.0},"33":{"tf":1.0},"36":{"tf":1.0},"40":{"tf":1.0},"44":{"tf":1.0},"72":{"tf":1.0},"83":{"tf":1.0}}}},"df":0,"docs":{}}}},"p":{"df":3,"docs":{"0":{"tf":1.0},"36":{"tf":1.0},"37":{"tf":1.0}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"e":{"df":1,"docs":{"66":{"tf":1.0}}}},"i":{"df":2,"docs":{"59":{"tf":1.0},"61":{"tf":1.0}},"v":{"df":0,"docs":{},"i":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"67":{"tf":1.0}}}},"df":0,"docs":{}}}},"u":{"df":0,"docs":{},"e":{"df":2,"docs":{"76":{"tf":1.4142135623730951},"88":{"tf":1.0}}}}},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":1,"docs":{"72":{"tf":1.0}}}}},"w":{"df":0,"docs":{},"o":{"df":3,"docs":{"40":{"tf":1.0},"47":{"tf":1.0},"6":{"tf":1.0}}}},"y":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"72":{"tf":1.0}}},"df":0,"docs":{}}}}},"u":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"48":{"tf":2.0}}}}},"l":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"62":{"tf":1.0}}}}}},"n":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"n":{"df":1,"docs":{"67":{"tf":1.0}}}}}}},"c":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":1,"docs":{"62":{"tf":1.0}}}}}},"df":0,"docs":{}},"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":4,"docs":{"19":{"tf":1.0},"3":{"tf":1.0},"59":{"tf":1.0},"64":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":3,"docs":{"40":{"tf":1.0},"49":{"tf":1.0},"75":{"tf":1.0}}}},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"31":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"d":{"df":1,"docs":{"1":{"tf":1.0}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{},"f":{"a":{"df":0,"docs":{},"v":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"72":{"tf":1.0}}}}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"d":{"df":1,"docs":{"88":{"tf":1.0}}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":1,"docs":{"23":{"tf":1.0}}}}}}}},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"w":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"77":{"tf":1.0}}}},"df":0,"docs":{}}},"t":{"df":1,"docs":{"74":{"tf":1.4142135623730951}},"i":{"df":1,"docs":{"53":{"tf":1.0}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"s":{"df":1,"docs":{"7":{"tf":1.0}}}}}}},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"36":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"k":{"df":3,"docs":{"14":{"tf":1.0},"18":{"tf":1.0},"67":{"tf":1.0}}},"n":{"df":0,"docs":{},"k":{"df":1,"docs":{"18":{"tf":1.7320508075688772}}}}}},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"16":{"tf":1.0}}}}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"60":{"tf":1.0}}}},"r":{"df":0,"docs":{},"u":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"34":{"tf":1.0}}}}}}},"u":{"df":0,"docs":{},"s":{"df":1,"docs":{"37":{"tf":1.0}}}},"w":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"61":{"tf":1.0}}}},"df":0,"docs":{}}}},"p":{"d":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"59":{"tf":1.7320508075688772}}}},"df":0,"docs":{}},"df":3,"docs":{"1":{"tf":1.0},"49":{"tf":1.0},"88":{"tf":1.0}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"m":{"df":2,"docs":{"60":{"tf":1.0},"68":{"tf":1.0}}}},"df":0,"docs":{}}}}}},"s":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"19":{"tf":1.0}}}},"df":0,"docs":{},"g":{"df":4,"docs":{"11":{"tf":1.4142135623730951},"51":{"tf":1.4142135623730951},"54":{"tf":1.0},"67":{"tf":1.0}}}},"df":32,"docs":{"13":{"tf":1.7320508075688772},"14":{"tf":1.4142135623730951},"15":{"tf":1.0},"16":{"tf":1.0},"17":{"tf":1.0},"18":{"tf":2.0},"25":{"tf":1.0},"27":{"tf":1.0},"30":{"tf":1.0},"37":{"tf":1.4142135623730951},"40":{"tf":1.7320508075688772},"45":{"tf":1.4142135623730951},"46":{"tf":1.0},"49":{"tf":1.4142135623730951},"5":{"tf":1.0},"50":{"tf":1.0},"52":{"tf":1.0},"58":{"tf":1.4142135623730951},"61":{"tf":1.7320508075688772},"62":{"tf":1.0},"63":{"tf":1.0},"64":{"tf":1.0},"65":{"tf":1.0},"66":{"tf":1.4142135623730951},"67":{"tf":1.0},"68":{"tf":2.0},"72":{"tf":1.0},"74":{"tf":1.0},"78":{"tf":1.0},"79":{"tf":1.0},"8":{"tf":1.0},"85":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":6,"docs":{"1":{"tf":1.0},"4":{"tf":1.0},"49":{"tf":1.0},"5":{"tf":1.0},"67":{"tf":1.0},"75":{"tf":1.0}}}},"u":{"a":{"df":0,"docs":{},"l":{"df":3,"docs":{"18":{"tf":1.0},"40":{"tf":1.0},"50":{"tf":1.0}}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":2,"docs":{"76":{"tf":1.0},"77":{"tf":1.0}}}}}},"v":{"0":{".":{"8":{".":{"0":{"df":1,"docs":{"89":{"tf":1.0}}},"df":0,"docs":{}},"df":1,"docs":{"4":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"df":0,"docs":{}},"1":{".":{"0":{".":{"0":{"df":1,"docs":{"89":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"d":{"df":4,"docs":{"12":{"tf":1.0},"36":{"tf":1.0},"45":{"tf":1.0},"72":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"u":{"df":8,"docs":{"13":{"tf":1.4142135623730951},"14":{"tf":1.4142135623730951},"26":{"tf":1.0},"27":{"tf":1.4142135623730951},"29":{"tf":1.0},"36":{"tf":1.0},"42":{"tf":1.0},"44":{"tf":1.0}},"e":{"_":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"d":{"(":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":1,"docs":{"54":{"tf":1.0}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"i":{"a":{"b":{"df":0,"docs":{},"l":{"df":5,"docs":{"13":{"tf":1.0},"48":{"tf":1.4142135623730951},"52":{"tf":1.0},"61":{"tf":1.0},"79":{"tf":1.0}}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"72":{"tf":1.0}}}}},"df":2,"docs":{"12":{"tf":1.0},"37":{"tf":1.0}},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"20":{"tf":1.0}}}}}}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"76":{"tf":1.0}}}}}}},"df":4,"docs":{"49":{"tf":1.0},"63":{"tf":1.0},"64":{"tf":1.0},"72":{"tf":1.4142135623730951}},"e":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"0":{"tf":1.0}}}}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":2,"docs":{"72":{"tf":1.0},"76":{"tf":1.0}},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"49":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":5,"docs":{"23":{"tf":1.0},"58":{"tf":1.0},"65":{"tf":1.0},"82":{"tf":2.0},"85":{"tf":2.0}}}}}}}},"i":{"a":{"df":10,"docs":{"47":{"tf":1.0},"48":{"tf":1.0},"60":{"tf":1.0},"65":{"tf":1.4142135623730951},"67":{"tf":1.0},"68":{"tf":1.0},"7":{"tf":1.0},"70":{"tf":1.0},"77":{"tf":1.0},"79":{"tf":1.4142135623730951}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"df":1,"docs":{"48":{"tf":1.4142135623730951}}}},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"48":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"88":{"tf":1.0}}}},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{".":{"df":0,"docs":{},"r":{"df":1,"docs":{"66":{"tf":1.0}}}},"df":1,"docs":{"66":{"tf":1.4142135623730951}}}}}},"u":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"64":{"tf":1.0}}}},"df":0,"docs":{}}}},"m":{"df":3,"docs":{"40":{"tf":1.0},"49":{"tf":1.4142135623730951},"72":{"tf":1.4142135623730951}}},"s":{"df":3,"docs":{"32":{"tf":1.0},"5":{"tf":1.0},"69":{"tf":1.0}}}},"w":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":3,"docs":{"54":{"tf":1.0},"66":{"tf":1.0},"68":{"tf":1.0}}}},"r":{"df":0,"docs":{},"m":{"df":1,"docs":{"0":{"tf":1.0}}},"n":{"df":6,"docs":{"0":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"18":{"tf":1.0},"38":{"tf":1.0},"40":{"tf":1.0}}}},"s":{"df":0,"docs":{},"m":{"df":4,"docs":{"7":{"tf":1.0},"72":{"tf":2.8284271247461903},"78":{"tf":1.0},"79":{"tf":1.7320508075688772}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"72":{"tf":1.4142135623730951}}}}}}},"y":{"df":2,"docs":{"74":{"tf":1.0},"80":{"tf":1.0}}}},"df":0,"docs":{},"e":{"b":{"3":{"df":1,"docs":{"88":{"tf":1.0}}},"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"b":{"df":0,"docs":{},"m":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"72":{"tf":1.0}}}}}},"df":0,"docs":{}}}}},"df":1,"docs":{"88":{"tf":1.0}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":1,"docs":{"54":{"tf":2.449489742783178}}}}}},"l":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"df":1,"docs":{"0":{"tf":1.4142135623730951}}}}},"df":0,"docs":{},"l":{"df":3,"docs":{"1":{"tf":1.0},"31":{"tf":1.0},"76":{"tf":1.0}}}},"’":{"d":{"df":2,"docs":{"49":{"tf":1.0},"62":{"tf":1.0}}},"df":0,"docs":{}}},"h":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":1,"docs":{"62":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":1,"docs":{"59":{"tf":1.0}}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":1,"docs":{"75":{"tf":1.0}}}}},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"62":{"tf":1.0}}}}}}},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":1,"docs":{"5":{"tf":1.0}}}}}},"i":{"df":0,"docs":{},"e":{"d":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"12":{"tf":1.0}}}}},"df":0,"docs":{}},"n":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":2,"docs":{"62":{"tf":1.0},"7":{"tf":1.0}}}}},"df":0,"docs":{}},"s":{"df":0,"docs":{},"h":{"df":1,"docs":{"62":{"tf":1.4142135623730951}}}}},"o":{"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"’":{"df":1,"docs":{"88":{"tf":1.0}}}},"df":0,"docs":{}},"r":{"d":{"df":2,"docs":{"5":{"tf":1.0},"61":{"tf":1.0}}},"df":0,"docs":{},"k":{"df":7,"docs":{"0":{"tf":1.4142135623730951},"18":{"tf":1.4142135623730951},"40":{"tf":1.4142135623730951},"49":{"tf":1.0},"66":{"tf":1.0},"69":{"tf":1.0},"87":{"tf":1.0}},"l":{"df":0,"docs":{},"o":{"a":{"d":{"df":1,"docs":{"72":{"tf":1.7320508075688772}}},"df":0,"docs":{}},"df":0,"docs":{}}},"s":{"df":0,"docs":{},"p":{"a":{"c":{"df":1,"docs":{"59":{"tf":1.7320508075688772}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"l":{"d":{"df":1,"docs":{"11":{"tf":1.0}}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"36":{"tf":1.0}}}},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"w":{"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"11":{"tf":1.0}}}}}}}}}},"r":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"68":{"tf":1.0},"76":{"tf":1.0}}}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":7,"docs":{"37":{"tf":1.0},"38":{"tf":1.0},"43":{"tf":1.0},"61":{"tf":1.0},"72":{"tf":1.0},"76":{"tf":1.0},"85":{"tf":1.0}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":2,"docs":{"49":{"tf":1.4142135623730951},"63":{"tf":1.0}}}}}}}}},"x":{"8":{"6":{"df":1,"docs":{"72":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{},"y":{"df":2,"docs":{"84":{"tf":1.0},"86":{"tf":1.0}}}},"y":{"df":0,"docs":{},"e":{"df":1,"docs":{"83":{"tf":1.0}}},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"f":{"df":1,"docs":{"62":{"tf":1.0}}}}}}},"’":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":1,"docs":{"58":{"tf":1.0}}}}}}},"u":{"df":0,"docs":{},"l":{"df":12,"docs":{"16":{"tf":1.0},"22":{"tf":1.0},"31":{"tf":1.0},"36":{"tf":1.4142135623730951},"47":{"tf":1.0},"5":{"tf":1.0},"6":{"tf":1.0},"63":{"tf":1.0},"64":{"tf":1.4142135623730951},"66":{"tf":1.7320508075688772},"69":{"tf":1.0},"83":{"tf":1.0}}}}},"z":{"df":1,"docs":{"12":{"tf":1.0}},"k":{"df":1,"docs":{"49":{"tf":1.0}}}}}},"breadcrumbs":{"root":{"0":{".":{"8":{".":{"0":{"df":1,"docs":{"82":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":5,"docs":{"12":{"tf":1.0},"38":{"tf":1.0},"48":{"tf":1.4142135623730951},"54":{"tf":3.4641016151377544},"76":{"tf":1.0}}},"1":{".":{"2":{"df":1,"docs":{"18":{"tf":1.0}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"s":{"df":1,"docs":{"14":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"/":{"1":{"0":{"0":{"df":1,"docs":{"72":{"tf":1.0}}},"df":1,"docs":{"72":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"2":{"8":{"df":0,"docs":{},"k":{"b":{"df":3,"docs":{"37":{"tf":1.4142135623730951},"38":{"tf":1.0},"43":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}},"3":{"1":{"0":{"7":{"2":{"df":2,"docs":{"13":{"tf":1.0},"14":{"tf":1.0}}},"df":0,"docs":{}},"8":{"8":{"df":1,"docs":{"54":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"2":{"1":{"6":{"df":1,"docs":{"54":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":5,"docs":{"12":{"tf":1.0},"36":{"tf":1.0},"48":{"tf":1.4142135623730951},"54":{"tf":1.4142135623730951},"72":{"tf":1.0}},"m":{"b":{"df":1,"docs":{"86":{"tf":1.0}}},"df":0,"docs":{}}},"2":{".":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":1,"docs":{"14":{"tf":1.0}}}}}},"4":{"5":{"6":{"6":{"6":{"9":{"df":1,"docs":{"54":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{},"k":{"b":{"df":1,"docs":{"86":{"tf":1.7320508075688772}}},"df":0,"docs":{}}},"5":{"0":{"0":{"0":{"0":{"0":{"0":{"0":{"0":{"0":{"0":{"0":{"0":{"0":{"0":{"df":1,"docs":{"44":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"6":{"df":1,"docs":{"69":{"tf":1.0}}},"df":0,"docs":{}},"9":{"3":{"7":{"6":{"3":{"4":{"df":1,"docs":{"54":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"^":{"3":{"2":{"df":1,"docs":{"36":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":2,"docs":{"12":{"tf":1.0},"72":{"tf":1.0}}},"3":{".":{"0":{"df":1,"docs":{"88":{"tf":1.0}}},"df":0,"docs":{}},"2":{"df":2,"docs":{"36":{"tf":1.0},"42":{"tf":1.0}}},"df":2,"docs":{"12":{"tf":1.0},"18":{"tf":1.4142135623730951}},"f":{"a":{"4":{"df":0,"docs":{},"f":{"2":{"4":{"5":{"df":1,"docs":{"76":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}},"4":{"0":{"8":{"4":{"4":{"8":{"3":{"df":1,"docs":{"54":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"2":{"9":{"4":{"8":{"3":{"6":{"0":{"9":{"6":{"df":1,"docs":{"54":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"5":{"5":{"1":{"0":{"6":{"1":{"5":{"df":1,"docs":{"54":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"6":{"3":{"/":{"6":{"4":{"df":2,"docs":{"0":{"tf":1.0},"34":{"tf":1.7320508075688772}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"4":{"df":1,"docs":{"69":{"tf":1.0}}},"df":0,"docs":{}},"9":{"8":{"5":{"2":{"0":{"9":{"df":1,"docs":{"54":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"d":{"df":1,"docs":{"48":{"tf":1.7320508075688772}}},"df":0,"docs":{}}}}}}}}}},"df":0,"docs":{}}}},"a":{"b":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"49":{"tf":1.0}}}}},"df":0,"docs":{}}},"b":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"df":1,"docs":{"61":{"tf":1.0}}}}}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"v":{"df":3,"docs":{"36":{"tf":1.0},"76":{"tf":1.0},"84":{"tf":1.0}}}}},"c":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":1,"docs":{"56":{"tf":1.0}}}},"s":{"df":0,"docs":{},"s":{"df":2,"docs":{"37":{"tf":1.0},"67":{"tf":1.0}}}}}},"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":1,"docs":{"20":{"tf":1.0}}}}}},"k":{"df":0,"docs":{},"n":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"d":{"df":0,"docs":{},"g":{"df":1,"docs":{"62":{"tf":1.0}}}},"df":0,"docs":{}}}}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"76":{"tf":1.7320508075688772}}}},"v":{"df":2,"docs":{"18":{"tf":1.0},"23":{"tf":1.0}}}},"u":{"a":{"df":0,"docs":{},"l":{"df":4,"docs":{"18":{"tf":1.0},"32":{"tf":1.0},"72":{"tf":1.0},"77":{"tf":1.0}}}},"df":0,"docs":{}}}},"d":{"d":{"df":2,"docs":{"59":{"tf":1.4142135623730951},"61":{"tf":1.0}},"i":{"df":0,"docs":{},"t":{"df":4,"docs":{"24":{"tf":1.0},"4":{"tf":1.0},"61":{"tf":1.4142135623730951},"69":{"tf":1.0}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{".":{"c":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"o":{"d":{"df":1,"docs":{"35":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":1,"docs":{"18":{"tf":1.4142135623730951}}}}}}},"df":1,"docs":{"59":{"tf":1.0}},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":1,"docs":{"49":{"tf":1.0}}}}},"v":{"a":{"df":0,"docs":{},"n":{"c":{"df":1,"docs":{"12":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"34":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{},"g":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"61":{"tf":1.0}},"s":{"df":0,"docs":{},"t":{"df":3,"docs":{"49":{"tf":1.0},"72":{"tf":1.0},"76":{"tf":1.4142135623730951}}}}}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"12":{"tf":1.4142135623730951}}}}}}}},"i":{"df":3,"docs":{"49":{"tf":1.4142135623730951},"61":{"tf":1.0},"62":{"tf":2.8284271247461903}},"m":{"df":4,"docs":{"11":{"tf":1.0},"75":{"tf":1.0},"87":{"tf":1.0},"89":{"tf":1.0}}}},"l":{"df":0,"docs":{},"g":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"m":{"df":1,"docs":{"49":{"tf":1.0}}}}}}}}},"i":{"a":{"df":0,"docs":{},"s":{"df":1,"docs":{"61":{"tf":1.0}}}},"df":0,"docs":{}},"l":{"df":0,"docs":{},"o":{"c":{"df":1,"docs":{"72":{"tf":1.0}}},"df":0,"docs":{},"w":{"df":7,"docs":{"26":{"tf":1.0},"27":{"tf":1.4142135623730951},"30":{"tf":1.0},"67":{"tf":1.0},"72":{"tf":1.0},"76":{"tf":1.0},"77":{"tf":1.0}}}}},"w":{"a":{"df":0,"docs":{},"y":{"df":10,"docs":{"18":{"tf":1.0},"36":{"tf":1.0},"38":{"tf":1.0},"40":{"tf":1.0},"47":{"tf":1.0},"59":{"tf":1.0},"61":{"tf":1.0},"68":{"tf":1.0},"75":{"tf":1.0},"85":{"tf":1.0}}}},"df":0,"docs":{}}},"m":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":4,"docs":{"0":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"34":{"tf":1.0}}}}}}},"n":{"df":0,"docs":{},"n":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"c":{"df":1,"docs":{"22":{"tf":1.0}}},"df":0,"docs":{}}}}},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":2,"docs":{"68":{"tf":1.0},"72":{"tf":1.0}}}}},"y":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"56":{"tf":1.0}}}}}},"p":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":1,"docs":{"40":{"tf":1.0}}}}},"df":0,"docs":{},"i":{"df":2,"docs":{"67":{"tf":1.0},"73":{"tf":1.4142135623730951}}},"p":{"df":1,"docs":{"88":{"tf":1.0}},"e":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"18":{"tf":1.0}}},"df":0,"docs":{}}},"l":{"df":0,"docs":{},"i":{"c":{"df":2,"docs":{"49":{"tf":1.4142135623730951},"5":{"tf":1.0}}},"df":7,"docs":{"12":{"tf":1.4142135623730951},"27":{"tf":1.0},"34":{"tf":1.0},"37":{"tf":1.0},"49":{"tf":1.0},"65":{"tf":1.0},"84":{"tf":1.0}}}},"r":{"df":0,"docs":{},"o":{"a":{"c":{"df":0,"docs":{},"h":{"df":2,"docs":{"63":{"tf":1.0},"77":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"74":{"tf":1.0}}}}}}}}},"r":{"b":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"30":{"tf":1.0}}}}},"df":0,"docs":{}}}}},"c":{"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":8,"docs":{"40":{"tf":1.0},"63":{"tf":1.7320508075688772},"64":{"tf":1.0},"65":{"tf":1.0},"66":{"tf":1.0},"67":{"tf":1.0},"68":{"tf":1.0},"69":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"u":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":4,"docs":{"30":{"tf":1.0},"36":{"tf":1.0},"40":{"tf":1.7320508075688772},"53":{"tf":1.0}}}}}}}},"m":{"df":1,"docs":{"72":{"tf":1.0}}},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"d":{"df":3,"docs":{"49":{"tf":1.0},"72":{"tf":1.4142135623730951},"86":{"tf":1.0}}},"df":0,"docs":{}}}},"t":{"df":1,"docs":{"72":{"tf":1.0}},"i":{"df":0,"docs":{},"f":{"a":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"16":{"tf":1.7320508075688772}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"s":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":4,"docs":{"55":{"tf":1.0},"58":{"tf":1.0},"61":{"tf":1.0},"62":{"tf":1.0}}}},"df":0,"docs":{}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"b":{"df":0,"docs":{},"l":{"df":5,"docs":{"16":{"tf":1.0},"36":{"tf":1.0},"4":{"tf":1.0},"40":{"tf":1.7320508075688772},"83":{"tf":1.7320508075688772}}}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"t":{"df":2,"docs":{"68":{"tf":1.0},"76":{"tf":1.0}}}},"t":{"df":1,"docs":{"73":{"tf":1.0}}}},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":2,"docs":{"61":{"tf":1.0},"62":{"tf":1.4142135623730951}}}}},"u":{"df":0,"docs":{},"m":{"df":2,"docs":{"40":{"tf":1.0},"47":{"tf":1.0}},"p":{"df":0,"docs":{},"t":{"df":1,"docs":{"72":{"tf":1.0}}}}}}},"t":{"df":1,"docs":{"66":{"tf":1.0}}}},"u":{"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"c":{"df":1,"docs":{"1":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"28":{"tf":1.0}}}}}}},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"36":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"t":{"df":2,"docs":{"53":{"tf":1.7320508075688772},"59":{"tf":1.0}}}},"df":0,"docs":{}}}}},"v":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":5,"docs":{"14":{"tf":1.0},"21":{"tf":1.0},"22":{"tf":1.0},"47":{"tf":1.0},"72":{"tf":1.0}}}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"i":{"d":{"df":3,"docs":{"53":{"tf":1.0},"59":{"tf":1.0},"61":{"tf":1.7320508075688772}}},"df":0,"docs":{}}}},"w":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"33":{"tf":1.0}}}},"df":0,"docs":{}}},"b":{"a":{"c":{"df":0,"docs":{},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"d":{"df":2,"docs":{"12":{"tf":1.0},"63":{"tf":1.0}}},"df":0,"docs":{}}},"w":{"a":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"73":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"n":{"c":{"df":2,"docs":{"63":{"tf":1.0},"76":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"k":{"df":1,"docs":{"72":{"tf":1.0}}}}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"88":{"tf":1.0}}}}}}},"s":{"df":0,"docs":{},"e":{"df":5,"docs":{"17":{"tf":1.0},"47":{"tf":1.0},"48":{"tf":1.0},"49":{"tf":1.0},"72":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"=":{"1":{"0":{"3":{"0":{"6":{"3":{"/":{"1":{"5":{"7":{"2":{"8":{"6":{"4":{"df":1,"docs":{"54":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"i":{"c":{"df":1,"docs":{"12":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":2,"docs":{"48":{"tf":1.0},"53":{"tf":1.0}}}}},"h":{"a":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":2,"docs":{"47":{"tf":1.0},"61":{"tf":1.0}}}}}}},"df":0,"docs":{}},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":2,"docs":{"72":{"tf":1.0},"88":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"w":{"df":3,"docs":{"18":{"tf":1.0},"36":{"tf":1.0},"89":{"tf":1.0}}}}},"n":{"c":{"df":0,"docs":{},"h":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"k":{"df":2,"docs":{"58":{"tf":1.0},"72":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"49":{"tf":1.0}}}}}}},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"61":{"tf":1.0}}}},"t":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"49":{"tf":1.0}}}}},"w":{"df":0,"docs":{},"e":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":5,"docs":{"12":{"tf":1.0},"32":{"tf":1.0},"47":{"tf":1.0},"63":{"tf":1.0},"69":{"tf":1.0}}}}}}},"y":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"d":{"df":2,"docs":{"49":{"tf":1.0},"74":{"tf":1.0}}},"df":0,"docs":{}}}}},"i":{"df":0,"docs":{},"g":{"df":1,"docs":{"67":{"tf":1.0}}},"n":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":7,"docs":{"5":{"tf":1.0},"50":{"tf":1.0},"64":{"tf":1.0},"65":{"tf":1.4142135623730951},"68":{"tf":1.0},"7":{"tf":1.7320508075688772},"78":{"tf":1.0}}}}},"df":1,"docs":{"19":{"tf":1.0}}},"t":{"df":3,"docs":{"36":{"tf":1.0},"59":{"tf":1.0},"69":{"tf":1.4142135623730951}},"w":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":1,"docs":{"76":{"tf":1.7320508075688772}}}}}}},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"62":{"tf":1.0}}}}},"df":0,"docs":{}}},"o":{"b":{"b":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":1,"docs":{"46":{"tf":1.4142135623730951}}}}}}},"df":0,"docs":{}},"df":6,"docs":{"18":{"tf":1.7320508075688772},"32":{"tf":1.4142135623730951},"46":{"tf":1.0},"64":{"tf":1.0},"65":{"tf":1.0},"89":{"tf":1.0}},"h":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"df":1,"docs":{"46":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}}},"c":{"df":0,"docs":{},"k":{"c":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":5,"docs":{"49":{"tf":1.0},"50":{"tf":1.4142135623730951},"72":{"tf":1.0},"73":{"tf":1.0},"77":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":1,"docs":{"40":{"tf":1.7320508075688772}}}},"df":0,"docs":{}}},"o":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"72":{"tf":1.0}}}},"o":{"df":0,"docs":{},"k":{"df":2,"docs":{"0":{"tf":1.0},"3":{"tf":1.4142135623730951}}},"l":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"n":{"df":1,"docs":{"26":{"tf":1.0}}}},"df":0,"docs":{}}}},"t":{"df":0,"docs":{},"h":{"df":2,"docs":{"18":{"tf":1.0},"32":{"tf":1.0}}}},"u":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"67":{"tf":1.0}}},"df":0,"docs":{}}}},"r":{"a":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"h":{"df":1,"docs":{"60":{"tf":1.7320508075688772}}}},"df":0,"docs":{}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"78":{"tf":1.0}}}}}}}},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"65":{"tf":1.0}}}},"df":0,"docs":{}}}}}},"u":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":5,"docs":{"14":{"tf":1.0},"36":{"tf":1.4142135623730951},"37":{"tf":1.4142135623730951},"40":{"tf":1.4142135623730951},"67":{"tf":1.4142135623730951}}}}}},"g":{"df":5,"docs":{"23":{"tf":1.0},"74":{"tf":1.0},"75":{"tf":1.7320508075688772},"76":{"tf":1.0},"77":{"tf":1.0}},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"x":{"df":1,"docs":{"85":{"tf":1.0}}}}}},"i":{"d":{"df":0,"docs":{},"l":{"df":1,"docs":{"10":{"tf":1.4142135623730951}}}},"df":0,"docs":{},"l":{"d":{"df":8,"docs":{"10":{"tf":1.0},"57":{"tf":1.0},"58":{"tf":1.0},"6":{"tf":1.0},"65":{"tf":2.0},"68":{"tf":2.0},"74":{"tf":1.0},"79":{"tf":2.449489742783178}},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"66":{"tf":1.0},"68":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"68":{"tf":1.0}}}},"t":{"df":1,"docs":{"68":{"tf":1.0}},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"68":{"tf":1.0}}}}}}},"n":{"d":{"df":0,"docs":{},"l":{"df":1,"docs":{"65":{"tf":1.0}}}},"df":0,"docs":{}},"s":{"df":0,"docs":{},"i":{"df":1,"docs":{"49":{"tf":1.0}}}}},"y":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"o":{"d":{"df":3,"docs":{"18":{"tf":1.0},"35":{"tf":1.0},"72":{"tf":2.23606797749979}}},"df":0,"docs":{}}},"df":2,"docs":{"37":{"tf":1.0},"67":{"tf":1.4142135623730951}}}}}},"c":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"_":{"d":{"a":{"df":0,"docs":{},"t":{"a":{"_":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"y":{"(":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":1,"docs":{"54":{"tf":1.0}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"s":{"df":1,"docs":{"54":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"18":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"d":{"a":{"df":0,"docs":{},"t":{"a":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":1,"docs":{"38":{"tf":1.4142135623730951}}}}}},"df":2,"docs":{"38":{"tf":1.0},"76":{"tf":1.0}},"l":{"df":0,"docs":{},"o":{"a":{"d":{"df":1,"docs":{"38":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":6,"docs":{"0":{"tf":1.0},"18":{"tf":1.0},"32":{"tf":1.0},"34":{"tf":1.0},"53":{"tf":1.0},"76":{"tf":1.4142135623730951}}}},"n":{"df":0,"docs":{},"’":{"df":0,"docs":{},"t":{"df":1,"docs":{"49":{"tf":1.0}}}}},"p":{"df":1,"docs":{"37":{"tf":1.0}},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":2,"docs":{"62":{"tf":1.4142135623730951},"69":{"tf":1.0}}}}}},"r":{"df":0,"docs":{},"e":{"df":2,"docs":{"18":{"tf":1.0},"63":{"tf":1.0}},"f":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"0":{"tf":1.0}}}}}}}},"g":{"df":0,"docs":{},"o":{".":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{"df":1,"docs":{"59":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":1,"docs":{"59":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"e":{"df":5,"docs":{"18":{"tf":2.0},"45":{"tf":1.0},"46":{"tf":1.0},"76":{"tf":1.4142135623730951},"77":{"tf":1.4142135623730951}}}},"u":{"df":0,"docs":{},"s":{"df":1,"docs":{"77":{"tf":1.0}}}},"v":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"37":{"tf":1.0}}}},"df":0,"docs":{}}}},"d":{"df":1,"docs":{"74":{"tf":1.0}}},"df":1,"docs":{"49":{"tf":1.0}},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"76":{"tf":1.0}}}},"df":0,"docs":{}}}}},"h":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":3,"docs":{"32":{"tf":1.0},"65":{"tf":1.0},"72":{"tf":1.4142135623730951}}}},"n":{"c":{"df":2,"docs":{"49":{"tf":1.0},"58":{"tf":1.0}}},"df":0,"docs":{},"g":{"df":6,"docs":{"18":{"tf":1.0},"3":{"tf":1.0},"34":{"tf":1.0},"59":{"tf":1.0},"60":{"tf":1.4142135623730951},"76":{"tf":1.4142135623730951}}}},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":4,"docs":{"11":{"tf":1.0},"55":{"tf":1.0},"74":{"tf":1.0},"83":{"tf":1.0}}}}}},"r":{"df":1,"docs":{"29":{"tf":1.0}}}},"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"k":{"df":2,"docs":{"67":{"tf":1.0},"85":{"tf":1.0}}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"49":{"tf":1.0}}},"df":0,"docs":{}}}},"i":{"df":2,"docs":{"58":{"tf":1.0},"60":{"tf":1.4142135623730951}},"r":{"c":{"df":0,"docs":{},"u":{"df":0,"docs":{},"m":{"df":0,"docs":{},"v":{"df":1,"docs":{"65":{"tf":1.0}}}}}},"df":0,"docs":{}}},"l":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":1,"docs":{"5":{"tf":1.0}}}}},"df":0,"docs":{},"i":{"df":2,"docs":{"11":{"tf":2.23606797749979},"18":{"tf":1.0}},"p":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":1,"docs":{"61":{"tf":1.0}}}}}},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":1,"docs":{"74":{"tf":1.0}}}},"s":{"df":0,"docs":{},"e":{"df":3,"docs":{"11":{"tf":1.0},"72":{"tf":1.0},"75":{"tf":1.0}}}}}},"o":{"d":{"df":0,"docs":{},"e":{"b":{"a":{"df":0,"docs":{},"s":{"df":4,"docs":{"55":{"tf":1.0},"58":{"tf":1.0},"59":{"tf":1.7320508075688772},"62":{"tf":1.7320508075688772}}}},"df":0,"docs":{}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":1,"docs":{"39":{"tf":1.4142135623730951}}}}}},"df":31,"docs":{"0":{"tf":1.0},"12":{"tf":1.4142135623730951},"13":{"tf":1.0},"14":{"tf":1.0},"17":{"tf":1.0},"18":{"tf":1.4142135623730951},"19":{"tf":1.0},"32":{"tf":3.3166247903554},"33":{"tf":1.0},"34":{"tf":1.0},"36":{"tf":1.0},"38":{"tf":1.0},"39":{"tf":1.0},"4":{"tf":1.0},"40":{"tf":2.23606797749979},"5":{"tf":1.0},"50":{"tf":1.4142135623730951},"6":{"tf":1.0},"61":{"tf":1.4142135623730951},"62":{"tf":1.0},"63":{"tf":1.0},"64":{"tf":1.4142135623730951},"65":{"tf":1.7320508075688772},"66":{"tf":1.4142135623730951},"67":{"tf":1.0},"72":{"tf":2.0},"74":{"tf":1.0},"75":{"tf":1.0},"76":{"tf":1.4142135623730951},"86":{"tf":1.0},"89":{"tf":1.4142135623730951}},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":2,"docs":{"47":{"tf":1.0},"48":{"tf":1.0}}}}},"s":{"df":1,"docs":{"32":{"tf":1.0}}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"76":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}}},"m":{"b":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":2,"docs":{"5":{"tf":1.0},"76":{"tf":1.4142135623730951}}}}},"df":0,"docs":{},"e":{"df":2,"docs":{"50":{"tf":1.0},"74":{"tf":1.0}}},"m":{"a":{"df":0,"docs":{},"n":{"d":{"df":10,"docs":{"11":{"tf":1.0},"12":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"15":{"tf":1.0},"16":{"tf":1.0},"17":{"tf":1.0},"18":{"tf":1.0},"19":{"tf":1.0},"30":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"61":{"tf":2.0}}}}},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"49":{"tf":1.0}}}}},"p":{"a":{"df":0,"docs":{},"r":{"df":2,"docs":{"31":{"tf":1.0},"37":{"tf":1.0}},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"0":{"tf":1.0}}}}}}},"t":{"df":8,"docs":{"24":{"tf":1.0},"63":{"tf":1.0},"67":{"tf":1.0},"73":{"tf":1.0},"75":{"tf":1.7320508075688772},"76":{"tf":1.0},"79":{"tf":1.0},"88":{"tf":1.0}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":48,"docs":{"0":{"tf":1.0},"12":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"16":{"tf":1.0},"18":{"tf":2.23606797749979},"19":{"tf":1.0},"22":{"tf":1.4142135623730951},"24":{"tf":1.0},"25":{"tf":1.0},"3":{"tf":1.0},"36":{"tf":1.0},"37":{"tf":1.0},"4":{"tf":1.7320508075688772},"45":{"tf":1.0},"46":{"tf":1.0},"47":{"tf":1.7320508075688772},"49":{"tf":1.0},"5":{"tf":2.0},"54":{"tf":1.0},"55":{"tf":1.0},"56":{"tf":1.0},"57":{"tf":1.0},"58":{"tf":1.0},"59":{"tf":1.0},"6":{"tf":1.7320508075688772},"62":{"tf":1.0},"63":{"tf":2.449489742783178},"64":{"tf":2.0},"65":{"tf":1.7320508075688772},"66":{"tf":2.23606797749979},"67":{"tf":1.4142135623730951},"68":{"tf":1.7320508075688772},"69":{"tf":1.0},"70":{"tf":1.0},"72":{"tf":2.23606797749979},"73":{"tf":1.0},"74":{"tf":1.0},"75":{"tf":1.4142135623730951},"76":{"tf":1.0},"77":{"tf":1.0},"78":{"tf":2.0},"79":{"tf":1.0},"8":{"tf":1.0},"80":{"tf":1.4142135623730951},"88":{"tf":1.4142135623730951},"89":{"tf":1.0},"9":{"tf":1.0}}}},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":3,"docs":{"11":{"tf":1.0},"72":{"tf":1.0},"89":{"tf":1.0}}},"x":{"df":2,"docs":{"49":{"tf":1.0},"77":{"tf":1.4142135623730951}}}},"i":{"c":{"df":1,"docs":{"59":{"tf":1.0}}},"df":0,"docs":{}}},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"5":{"tf":1.4142135623730951}}},"s":{"df":1,"docs":{"49":{"tf":1.0}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":2,"docs":{"58":{"tf":1.0},"77":{"tf":1.0}}}}}}}},"t":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"4":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}},"u":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"49":{"tf":1.0}}}}}}},"df":1,"docs":{"72":{"tf":1.0}}}}}},"n":{"c":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"40":{"tf":1.0}}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":1,"docs":{"58":{"tf":1.0}}}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":7,"docs":{"13":{"tf":1.0},"14":{"tf":1.0},"24":{"tf":1.0},"25":{"tf":1.0},"27":{"tf":1.7320508075688772},"29":{"tf":1.0},"71":{"tf":1.7320508075688772}}}}}},"l":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"61":{"tf":1.0}}}},"df":0,"docs":{}}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"q":{"df":0,"docs":{},"u":{"df":1,"docs":{"18":{"tf":1.0}},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"14":{"tf":1.0}}}}}}}}},"i":{"d":{"df":5,"docs":{"59":{"tf":1.0},"61":{"tf":1.0},"65":{"tf":1.0},"73":{"tf":1.0},"87":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"49":{"tf":1.0}}}}},"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":2,"docs":{"62":{"tf":1.0},"72":{"tf":1.0}}}}},"t":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":5,"docs":{"14":{"tf":1.0},"40":{"tf":1.0},"42":{"tf":1.0},"44":{"tf":1.0},"61":{"tf":1.0}}}}},"df":0,"docs":{},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"53":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"u":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":6,"docs":{"32":{"tf":1.4142135623730951},"38":{"tf":1.0},"39":{"tf":1.0},"40":{"tf":1.7320508075688772},"48":{"tf":1.7320508075688772},"53":{"tf":1.0}}}}}},"df":0,"docs":{}}}}},"t":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":3,"docs":{"36":{"tf":1.0},"40":{"tf":1.0},"5":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"3":{"tf":1.0}}}},"x":{"df":0,"docs":{},"t":{"df":2,"docs":{"62":{"tf":1.0},"66":{"tf":2.0}}}}},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":32,"docs":{"0":{"tf":2.0},"12":{"tf":1.0},"13":{"tf":1.7320508075688772},"14":{"tf":2.0},"18":{"tf":2.0},"2":{"tf":1.7320508075688772},"27":{"tf":1.4142135623730951},"32":{"tf":1.4142135623730951},"34":{"tf":1.0},"36":{"tf":1.0},"37":{"tf":1.7320508075688772},"4":{"tf":1.4142135623730951},"40":{"tf":2.0},"41":{"tf":1.0},"42":{"tf":1.0},"47":{"tf":1.0},"48":{"tf":1.4142135623730951},"49":{"tf":2.0},"50":{"tf":1.4142135623730951},"52":{"tf":1.0},"53":{"tf":1.7320508075688772},"54":{"tf":1.4142135623730951},"6":{"tf":1.0},"63":{"tf":1.4142135623730951},"65":{"tf":2.23606797749979},"67":{"tf":1.0},"72":{"tf":2.23606797749979},"73":{"tf":1.0},"75":{"tf":1.4142135623730951},"76":{"tf":2.0},"86":{"tf":1.4142135623730951},"88":{"tf":1.4142135623730951}},"s":{".":{"df":0,"docs":{},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"k":{"a":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{".":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":1,"docs":{"2":{"tf":1.0}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"’":{"df":2,"docs":{"13":{"tf":1.0},"14":{"tf":1.0}}}}},"df":0,"docs":{}},"df":0,"docs":{},"i":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":5,"docs":{"13":{"tf":1.0},"14":{"tf":1.0},"56":{"tf":1.0},"60":{"tf":1.7320508075688772},"62":{"tf":2.0}},"o":{"df":0,"docs":{},"r":{"df":10,"docs":{"1":{"tf":1.0},"55":{"tf":1.0},"56":{"tf":1.7320508075688772},"57":{"tf":1.0},"58":{"tf":1.0},"59":{"tf":1.0},"60":{"tf":1.0},"61":{"tf":1.0},"62":{"tf":1.4142135623730951},"74":{"tf":1.0}}}}}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"l":{"df":4,"docs":{"13":{"tf":1.0},"52":{"tf":1.0},"67":{"tf":1.0},"79":{"tf":1.0}}}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":3,"docs":{"49":{"tf":1.0},"50":{"tf":1.0},"52":{"tf":1.0}}}}}}},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":3,"docs":{"62":{"tf":1.0},"74":{"tf":1.4142135623730951},"76":{"tf":1.0}}}},"df":0,"docs":{},"s":{"df":0,"docs":{},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"d":{"df":4,"docs":{"18":{"tf":1.0},"26":{"tf":1.0},"27":{"tf":1.4142135623730951},"29":{"tf":1.0}}},"df":0,"docs":{}}}}}}}},"s":{"df":0,"docs":{},"t":{"df":3,"docs":{"13":{"tf":1.4142135623730951},"14":{"tf":1.7320508075688772},"40":{"tf":1.0}}}},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"61":{"tf":1.0}},"p":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":1,"docs":{"76":{"tf":1.0}}}}},"df":0,"docs":{}}}}}},"p":{"df":0,"docs":{},"l":{"df":1,"docs":{"49":{"tf":1.0}}}},"r":{"df":0,"docs":{},"s":{"df":1,"docs":{"49":{"tf":1.0}}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"55":{"tf":1.0}}}}}},"p":{"df":0,"docs":{},"u":{"df":2,"docs":{"71":{"tf":1.7320508075688772},"72":{"tf":1.4142135623730951}}}},"r":{"a":{"df":0,"docs":{},"f":{"df":0,"docs":{},"t":{"df":1,"docs":{"40":{"tf":1.0}}}},"t":{"df":0,"docs":{},"e":{"df":3,"docs":{"59":{"tf":2.449489742783178},"66":{"tf":1.7320508075688772},"68":{"tf":1.4142135623730951}},"s":{"/":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"g":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"/":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"s":{"/":{"df":0,"docs":{},"f":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"p":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{".":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":1,"docs":{"19":{"tf":1.0}}}}}},"df":0,"docs":{}}}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"t":{"df":4,"docs":{"40":{"tf":2.0},"59":{"tf":1.0},"62":{"tf":1.0},"77":{"tf":1.0}},"e":{"2":{"df":1,"docs":{"40":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"77":{"tf":1.0}}}}}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":5,"docs":{"58":{"tf":1.0},"68":{"tf":1.4142135623730951},"78":{"tf":2.0},"79":{"tf":1.0},"80":{"tf":1.7320508075688772}}}}},"u":{"c":{"df":0,"docs":{},"i":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"65":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"86":{"tf":1.0}}}}}}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"df":3,"docs":{"68":{"tf":1.0},"69":{"tf":1.7320508075688772},"89":{"tf":1.0}}}}}}}},"d":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"p":{"df":7,"docs":{"1":{"tf":1.0},"18":{"tf":1.0},"31":{"tf":1.0},"36":{"tf":1.0},"49":{"tf":1.4142135623730951},"85":{"tf":1.4142135623730951},"88":{"tf":1.4142135623730951}}}},"t":{"a":{"_":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"54":{"tf":1.4142135623730951}}}}},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":1,"docs":{"54":{"tf":1.4142135623730951}}}}}},"df":6,"docs":{"18":{"tf":1.0},"32":{"tf":1.0},"46":{"tf":1.0},"54":{"tf":2.0},"67":{"tf":1.0},"76":{"tf":1.4142135623730951}},"o":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":2,"docs":{"40":{"tf":1.0},"41":{"tf":1.4142135623730951}}}}}}}},"s":{"df":2,"docs":{"40":{"tf":1.0},"42":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}},"df":0,"docs":{},"e":{"a":{"d":{"df":1,"docs":{"49":{"tf":1.0}}},"df":0,"docs":{},"l":{"df":1,"docs":{"36":{"tf":1.0}}}},"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"_":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":0,"docs":{},"p":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"_":{"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"16":{"tf":1.0}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}},"df":6,"docs":{"16":{"tf":2.0},"17":{"tf":2.0},"26":{"tf":1.0},"30":{"tf":1.0},"50":{"tf":1.0},"54":{"tf":1.0}}}}},"c":{"df":0,"docs":{},"i":{"d":{"df":2,"docs":{"18":{"tf":1.0},"77":{"tf":1.0}}},"df":0,"docs":{},"s":{"df":3,"docs":{"61":{"tf":1.0},"72":{"tf":1.0},"88":{"tf":1.0}}}},"l":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"76":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":1,"docs":{"66":{"tf":1.0}}}}}}},"d":{"df":0,"docs":{},"i":{"c":{"df":2,"docs":{"59":{"tf":1.0},"66":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"f":{"a":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":5,"docs":{"12":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"15":{"tf":1.0},"17":{"tf":1.0}}}}}},"df":0,"docs":{},"i":{"df":1,"docs":{"49":{"tf":1.0}},"n":{"df":2,"docs":{"74":{"tf":1.0},"76":{"tf":2.0}}}},"u":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"0":{"tf":1.0}}}},"df":0,"docs":{}}}},"g":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":2,"docs":{"61":{"tf":1.0},"62":{"tf":1.0}}}}},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"g":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"c":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"18":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"t":{"df":1,"docs":{"61":{"tf":1.0}}}},"i":{"df":0,"docs":{},"v":{"df":1,"docs":{"89":{"tf":1.0}}}}},"n":{"df":0,"docs":{},"i":{"df":1,"docs":{"60":{"tf":1.0}}}},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"d":{"df":6,"docs":{"18":{"tf":1.4142135623730951},"59":{"tf":3.0},"65":{"tf":1.0},"68":{"tf":2.0},"79":{"tf":1.7320508075688772},"8":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"y":{"df":5,"docs":{"18":{"tf":3.3166247903554},"31":{"tf":1.0},"32":{"tf":2.0},"40":{"tf":2.23606797749979},"86":{"tf":1.4142135623730951}}}}},"r":{"df":0,"docs":{},"e":{"c":{"df":1,"docs":{"49":{"tf":1.0}}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":1,"docs":{"48":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"n":{"df":3,"docs":{"49":{"tf":1.0},"61":{"tf":1.0},"72":{"tf":1.4142135623730951}}}},"r":{"df":1,"docs":{"50":{"tf":1.0}}}},"t":{"df":1,"docs":{"76":{"tf":1.0}}}},"t":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":2,"docs":{"11":{"tf":1.0},"77":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"37":{"tf":1.0}}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"65":{"tf":1.0}}}}}}}}}}},"v":{"df":2,"docs":{"50":{"tf":1.0},"59":{"tf":1.4142135623730951}},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":34,"docs":{"1":{"tf":1.4142135623730951},"16":{"tf":1.0},"17":{"tf":1.0},"20":{"tf":1.0},"30":{"tf":1.0},"31":{"tf":1.0},"49":{"tf":1.0},"55":{"tf":1.7320508075688772},"56":{"tf":1.0},"57":{"tf":1.0},"58":{"tf":1.7320508075688772},"59":{"tf":1.0},"60":{"tf":1.0},"61":{"tf":1.0},"62":{"tf":1.0},"63":{"tf":1.0},"64":{"tf":1.0},"65":{"tf":1.0},"66":{"tf":1.0},"67":{"tf":1.0},"68":{"tf":1.0},"69":{"tf":1.0},"70":{"tf":1.0},"71":{"tf":1.0},"72":{"tf":1.0},"73":{"tf":1.0},"74":{"tf":1.0},"75":{"tf":1.0},"76":{"tf":1.0},"77":{"tf":1.0},"78":{"tf":1.0},"79":{"tf":1.0},"80":{"tf":1.0},"89":{"tf":1.0}}}}}}}},"i":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"31":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":23,"docs":{"0":{"tf":2.23606797749979},"1":{"tf":1.0},"12":{"tf":1.0},"31":{"tf":2.0},"32":{"tf":1.0},"33":{"tf":1.4142135623730951},"34":{"tf":1.0},"35":{"tf":1.0},"36":{"tf":1.4142135623730951},"37":{"tf":1.4142135623730951},"38":{"tf":1.0},"39":{"tf":1.0},"40":{"tf":1.7320508075688772},"41":{"tf":1.0},"42":{"tf":1.0},"43":{"tf":1.0},"44":{"tf":1.0},"45":{"tf":1.0},"46":{"tf":1.0},"47":{"tf":2.23606797749979},"48":{"tf":1.0},"75":{"tf":1.0},"83":{"tf":1.0}},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":4,"docs":{"32":{"tf":1.0},"65":{"tf":1.0},"76":{"tf":3.1622776601683795},"77":{"tf":2.23606797749979}}}}}}}},"i":{"c":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"44":{"tf":1.4142135623730951}}}}}}},"df":0,"docs":{}}}},"r":{"df":2,"docs":{"16":{"tf":1.0},"59":{"tf":1.0}},"e":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"19":{"tf":1.0}}}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":4,"docs":{"16":{"tf":1.0},"18":{"tf":1.4142135623730951},"51":{"tf":1.0},"59":{"tf":1.0}}}}}}},"df":0,"docs":{}}},"s":{"a":{"b":{"df":0,"docs":{},"l":{"df":2,"docs":{"17":{"tf":1.0},"18":{"tf":1.0}}}},"df":0,"docs":{}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"g":{"df":2,"docs":{"18":{"tf":1.4142135623730951},"40":{"tf":1.0}}}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":2,"docs":{"60":{"tf":1.0},"62":{"tf":1.0}}}}}},"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":2,"docs":{"68":{"tf":1.0},"9":{"tf":1.0}}}}},"df":0,"docs":{}}}}}},"o":{"c":{"df":1,"docs":{"61":{"tf":1.0}},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"80":{"tf":1.0}}}}}}}},"u":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":2,"docs":{"3":{"tf":1.0},"8":{"tf":1.0}}}}}}}},"df":1,"docs":{"0":{"tf":1.0}},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"n":{"df":0,"docs":{},"’":{"df":0,"docs":{},"t":{"df":5,"docs":{"19":{"tf":1.0},"34":{"tf":1.0},"59":{"tf":1.0},"61":{"tf":1.0},"67":{"tf":1.0}}}}}}},"m":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"69":{"tf":1.0}}}}},"df":0,"docs":{}},"n":{"df":0,"docs":{},"e":{"df":1,"docs":{"18":{"tf":1.0}}},"’":{"df":0,"docs":{},"t":{"df":5,"docs":{"36":{"tf":1.0},"59":{"tf":1.0},"61":{"tf":1.4142135623730951},"68":{"tf":1.0},"82":{"tf":1.0}}}}},"w":{"df":0,"docs":{},"n":{"df":2,"docs":{"50":{"tf":1.0},"72":{"tf":1.0}}}}},"r":{"df":1,"docs":{"88":{"tf":1.0}},"i":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":3,"docs":{"19":{"tf":1.0},"5":{"tf":1.0},"64":{"tf":1.0}}}}}},"o":{"df":0,"docs":{},"p":{"df":1,"docs":{"87":{"tf":1.7320508075688772}}}}},"u":{"df":0,"docs":{},"e":{"df":7,"docs":{"13":{"tf":1.0},"14":{"tf":1.0},"18":{"tf":1.7320508075688772},"40":{"tf":1.0},"65":{"tf":1.0},"69":{"tf":1.0},"75":{"tf":1.0}}},"m":{"df":0,"docs":{},"p":{"df":1,"docs":{"16":{"tf":1.0}}}},"r":{"df":0,"docs":{},"e":{"df":3,"docs":{"18":{"tf":1.4142135623730951},"68":{"tf":1.0},"8":{"tf":1.0}}}}},"y":{"df":0,"docs":{},"n":{"a":{"df":0,"docs":{},"m":{"df":2,"docs":{"14":{"tf":1.0},"65":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{},"e":{"a":{"c":{"df":0,"docs":{},"h":{"df":2,"docs":{"49":{"tf":1.0},"76":{"tf":1.4142135623730951}}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"77":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"i":{"df":1,"docs":{"5":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":2,"docs":{"49":{"tf":1.0},"61":{"tf":1.0}}}}}}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"s":{"df":0,"docs":{},"y":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":1,"docs":{"88":{"tf":1.0}}}}}}}}}},"d":{"df":0,"docs":{},"g":{"df":1,"docs":{"88":{"tf":1.0}}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":2,"docs":{"72":{"tf":1.0},"76":{"tf":1.0}}}},"df":0,"docs":{}},"i":{"c":{"df":0,"docs":{},"i":{"df":1,"docs":{"72":{"tf":1.0}}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":4,"docs":{"49":{"tf":1.0},"61":{"tf":1.0},"63":{"tf":1.0},"88":{"tf":1.0}}}}}}},"l":{"df":0,"docs":{},"f":{"df":5,"docs":{"16":{"tf":1.0},"18":{"tf":1.4142135623730951},"64":{"tf":1.4142135623730951},"71":{"tf":1.0},"78":{"tf":1.0}}},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":2,"docs":{"77":{"tf":1.0},"88":{"tf":1.0}}}}}}},"m":{"b":{"df":0,"docs":{},"e":{"d":{"df":1,"docs":{"72":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":7,"docs":{"18":{"tf":1.0},"32":{"tf":1.0},"36":{"tf":1.0},"64":{"tf":1.0},"66":{"tf":1.0},"67":{"tf":1.4142135623730951},"89":{"tf":1.4142135623730951}}}},"p":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"y":{"df":1,"docs":{"65":{"tf":1.0}}}}},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"54":{"tf":1.0}}}}},"s":{"c":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":3,"docs":{"68":{"tf":1.0},"7":{"tf":1.0},"79":{"tf":1.7320508075688772}}}}}}}}},"d":{"df":0,"docs":{},"k":{"/":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":0,"docs":{},"s":{"d":{"df":0,"docs":{},"k":{"_":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"v":{".":{"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"df":1,"docs":{"79":{"tf":1.0}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":1,"docs":{"79":{"tf":1.0}}}},"df":0,"docs":{}},"u":{"df":0,"docs":{},"l":{"df":3,"docs":{"14":{"tf":1.0},"37":{"tf":1.0},"67":{"tf":1.0}}}}},"n":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"26":{"tf":1.0}}}},"df":0,"docs":{}},"c":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"s":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":2,"docs":{"58":{"tf":1.0},"66":{"tf":1.0}}}}}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"g":{"df":1,"docs":{"74":{"tf":1.0}}}},"df":0,"docs":{}}}}},"d":{"df":1,"docs":{"49":{"tf":1.4142135623730951}},"i":{"a":{"df":0,"docs":{},"n":{"df":1,"docs":{"67":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":2,"docs":{"49":{"tf":1.0},"63":{"tf":1.0}}}},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"df":1,"docs":{"61":{"tf":1.0}}}}}}},"j":{"df":0,"docs":{},"o":{"df":0,"docs":{},"y":{"df":1,"docs":{"62":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":2,"docs":{"61":{"tf":1.0},"62":{"tf":1.0}}}}}},"s":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":3,"docs":{"60":{"tf":1.0},"65":{"tf":1.0},"76":{"tf":1.4142135623730951}}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"r":{"df":1,"docs":{"72":{"tf":1.0}}}},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"88":{"tf":1.0}}},"y":{"df":0,"docs":{},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"5":{"tf":1.0}}}}}}}}}},"v":{"df":1,"docs":{"79":{"tf":1.0}},"i":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":6,"docs":{"50":{"tf":1.0},"52":{"tf":1.0},"69":{"tf":1.0},"73":{"tf":2.0},"78":{"tf":1.0},"79":{"tf":1.4142135623730951}}}}}}}},"q":{"df":0,"docs":{},"u":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"32":{"tf":1.0}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"l":{"df":2,"docs":{"4":{"tf":1.0},"72":{"tf":1.0}}}},"df":0,"docs":{}}}}},"r":{"df":0,"docs":{},"r":{"(":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{":":{":":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"(":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"d":{"a":{"df":0,"docs":{},"t":{"a":{"df":1,"docs":{"54":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":5,"docs":{"36":{"tf":1.0},"37":{"tf":1.0},"45":{"tf":1.0},"46":{"tf":1.0},"76":{"tf":1.0}}}}}},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"u":{"df":0,"docs":{},"m":{"/":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"d":{"/":{"b":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"/":{":":{"$":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"74":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":13,"docs":{"0":{"tf":1.0},"11":{"tf":1.0},"31":{"tf":1.0},"37":{"tf":1.0},"4":{"tf":1.0},"46":{"tf":1.0},"6":{"tf":1.0},"63":{"tf":1.4142135623730951},"74":{"tf":1.7320508075688772},"75":{"tf":1.7320508075688772},"76":{"tf":2.23606797749979},"8":{"tf":1.0},"88":{"tf":1.0}}}}}}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":4,"docs":{"49":{"tf":1.0},"62":{"tf":1.0},"72":{"tf":1.0},"88":{"tf":1.0}},"t":{"df":0,"docs":{},"u":{"df":2,"docs":{"13":{"tf":1.0},"14":{"tf":1.0}}}}}},"m":{"df":31,"docs":{"0":{"tf":1.4142135623730951},"1":{"tf":1.0},"14":{"tf":1.4142135623730951},"31":{"tf":2.0},"32":{"tf":1.4142135623730951},"33":{"tf":1.0},"34":{"tf":1.0},"35":{"tf":1.0},"36":{"tf":1.0},"37":{"tf":1.7320508075688772},"38":{"tf":1.0},"39":{"tf":1.0},"4":{"tf":1.0},"40":{"tf":1.7320508075688772},"41":{"tf":1.0},"42":{"tf":1.0},"43":{"tf":1.0},"44":{"tf":1.0},"45":{"tf":1.4142135623730951},"46":{"tf":1.0},"47":{"tf":1.0},"48":{"tf":1.4142135623730951},"49":{"tf":1.7320508075688772},"67":{"tf":2.23606797749979},"69":{"tf":1.4142135623730951},"72":{"tf":2.23606797749979},"74":{"tf":1.0},"75":{"tf":1.0},"76":{"tf":2.6457513110645907},"82":{"tf":1.7320508075688772},"86":{"tf":1.0}}}},"x":{"a":{"c":{"df":0,"docs":{},"t":{"df":3,"docs":{"18":{"tf":1.0},"71":{"tf":1.0},"77":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":2,"docs":{"65":{"tf":1.0},"76":{"tf":1.0}}}}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":13,"docs":{"0":{"tf":1.0},"18":{"tf":1.0},"48":{"tf":1.4142135623730951},"49":{"tf":1.4142135623730951},"5":{"tf":1.0},"54":{"tf":1.4142135623730951},"58":{"tf":1.0},"60":{"tf":1.0},"65":{"tf":1.0},"76":{"tf":1.4142135623730951},"77":{"tf":1.0},"79":{"tf":1.0},"80":{"tf":1.0}}}}}},"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":1,"docs":{"49":{"tf":1.0}}},"p":{"df":0,"docs":{},"t":{"df":1,"docs":{"60":{"tf":1.0}}}}}},"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":15,"docs":{"12":{"tf":1.7320508075688772},"13":{"tf":1.0},"14":{"tf":1.0},"15":{"tf":1.0},"36":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.4142135623730951},"52":{"tf":1.4142135623730951},"54":{"tf":1.0},"72":{"tf":1.4142135623730951},"76":{"tf":2.449489742783178},"77":{"tf":1.0},"78":{"tf":1.0},"79":{"tf":1.0},"80":{"tf":1.0}}}}},"df":0,"docs":{}},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":2,"docs":{"11":{"tf":1.0},"86":{"tf":1.0}}}}},"p":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":4,"docs":{"40":{"tf":1.4142135623730951},"49":{"tf":1.0},"61":{"tf":1.0},"76":{"tf":1.4142135623730951}}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":2,"docs":{"49":{"tf":1.0},"72":{"tf":1.7320508075688772}}}},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"49":{"tf":1.0}}}}},"l":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":4,"docs":{"11":{"tf":1.0},"18":{"tf":1.0},"61":{"tf":1.0},"74":{"tf":1.0}}}}},"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"18":{"tf":1.0}}}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}}},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"14":{"tf":1.0}}}}}}},"r":{"df":0,"docs":{},"t":{"df":2,"docs":{"74":{"tf":1.0},"79":{"tf":1.4142135623730951}}}},"s":{"df":3,"docs":{"12":{"tf":1.0},"19":{"tf":1.0},"73":{"tf":1.0}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"61":{"tf":1.7320508075688772}}}}}}},"t":{"c":{"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":1,"docs":{"45":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":1,"docs":{"18":{"tf":1.4142135623730951}}}}}}}},"f":{"a":{"c":{"df":0,"docs":{},"e":{"df":1,"docs":{"5":{"tf":1.0}}},"t":{"df":3,"docs":{"18":{"tf":1.0},"62":{"tf":1.0},"72":{"tf":1.0}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"18":{"tf":1.4142135623730951}}}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":3,"docs":{"18":{"tf":1.4142135623730951},"62":{"tf":1.0},"86":{"tf":1.4142135623730951}}}},"l":{"df":0,"docs":{},"l":{"df":2,"docs":{"40":{"tf":1.0},"72":{"tf":1.0}}}},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"40":{"tf":1.0}}}}}},"q":{"df":7,"docs":{"81":{"tf":1.7320508075688772},"82":{"tf":1.0},"83":{"tf":1.0},"84":{"tf":1.0},"85":{"tf":1.0},"86":{"tf":1.0},"87":{"tf":1.0}}},"r":{"df":2,"docs":{"49":{"tf":1.0},"72":{"tf":1.0}}},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"49":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"4":{"tf":1.0},"72":{"tf":1.0}}}}}}},"df":1,"docs":{"54":{"tf":1.0}},"e":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"63":{"tf":1.0}}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":6,"docs":{"18":{"tf":1.0},"4":{"tf":1.0},"74":{"tf":1.0},"83":{"tf":1.0},"85":{"tf":1.0},"89":{"tf":1.0}}}}}},"df":0,"docs":{},"w":{"df":4,"docs":{"11":{"tf":1.0},"24":{"tf":1.0},"37":{"tf":1.0},"61":{"tf":1.0}}}},"i":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":5,"docs":{"16":{"tf":1.0},"17":{"tf":1.0},"54":{"tf":1.0},"59":{"tf":1.4142135623730951},"64":{"tf":1.0}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"52":{"tf":1.0}}}}}},"n":{"a":{"df":0,"docs":{},"l":{"df":3,"docs":{"64":{"tf":1.0},"76":{"tf":1.0},"79":{"tf":1.4142135623730951}}}},"d":{"df":3,"docs":{"1":{"tf":1.0},"7":{"tf":1.0},"85":{"tf":1.0}}},"df":0,"docs":{},"e":{"df":6,"docs":{"0":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"52":{"tf":1.0},"58":{"tf":1.0},"65":{"tf":1.0}}},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"df":1,"docs":{"54":{"tf":1.4142135623730951}}}},"t":{"df":1,"docs":{"14":{"tf":1.0}}}}},"r":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"89":{"tf":1.0}}}}},"x":{"df":5,"docs":{"0":{"tf":1.4142135623730951},"37":{"tf":1.4142135623730951},"60":{"tf":1.0},"62":{"tf":1.0},"74":{"tf":1.0}}}},"l":{"a":{"df":0,"docs":{},"g":{"df":3,"docs":{"18":{"tf":1.0},"54":{"tf":2.0},"67":{"tf":1.0}}},"w":{"df":1,"docs":{"72":{"tf":1.4142135623730951}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"p":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{".":{"df":0,"docs":{},"p":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{"df":1,"docs":{"54":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}}}}}}},"o":{"c":{"df":0,"docs":{},"u":{"df":1,"docs":{"89":{"tf":1.0}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":13,"docs":{"10":{"tf":1.0},"12":{"tf":1.0},"33":{"tf":1.0},"49":{"tf":1.0},"6":{"tf":1.0},"61":{"tf":1.0},"62":{"tf":1.0},"64":{"tf":1.4142135623730951},"65":{"tf":1.0},"7":{"tf":1.0},"75":{"tf":1.0},"76":{"tf":1.0},"77":{"tf":1.0}}}}}},"r":{"c":{"df":1,"docs":{"60":{"tf":1.0}}},"df":0,"docs":{},"k":{"df":2,"docs":{"21":{"tf":1.7320508075688772},"23":{"tf":1.0}}},"m":{"a":{"df":0,"docs":{},"t":{"df":3,"docs":{"18":{"tf":1.0},"76":{"tf":1.0},"77":{"tf":1.0}},"t":{"df":1,"docs":{"61":{"tf":1.0}}}}},"df":0,"docs":{}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"e":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"62":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"u":{"df":0,"docs":{},"m":{"df":1,"docs":{"22":{"tf":1.0}}}}},"u":{"df":0,"docs":{},"n":{"d":{"df":5,"docs":{"18":{"tf":1.0},"3":{"tf":1.0},"59":{"tf":1.0},"71":{"tf":1.0},"72":{"tf":1.0}},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"21":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}}}},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"72":{"tf":1.0}}}}}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":1,"docs":{"54":{"tf":1.4142135623730951}},"w":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"k":{"df":1,"docs":{"63":{"tf":1.0}}}}}}}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"d":{"df":5,"docs":{"5":{"tf":1.0},"6":{"tf":1.0},"63":{"tf":1.0},"78":{"tf":1.0},"79":{"tf":1.0}}},"df":0,"docs":{}}}}}}},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":4,"docs":{"60":{"tf":1.0},"61":{"tf":1.0},"65":{"tf":1.4142135623730951},"71":{"tf":1.0}}}}},"n":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":6,"docs":{"36":{"tf":2.0},"37":{"tf":1.4142135623730951},"48":{"tf":1.4142135623730951},"61":{"tf":1.4142135623730951},"68":{"tf":1.0},"89":{"tf":1.0}}}}}}},"d":{"df":1,"docs":{"62":{"tf":1.0}}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":3,"docs":{"76":{"tf":1.0},"77":{"tf":1.0},"86":{"tf":1.0}},"m":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":2,"docs":{"68":{"tf":1.0},"69":{"tf":1.0}}}}}}}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"40":{"tf":1.0}}}},"u":{"df":0,"docs":{},"r":{"df":3,"docs":{"18":{"tf":1.0},"62":{"tf":1.0},"86":{"tf":1.0}}}}}}},"g":{"a":{"df":8,"docs":{"0":{"tf":1.7320508075688772},"13":{"tf":1.0},"14":{"tf":1.4142135623730951},"34":{"tf":2.0},"37":{"tf":1.0},"40":{"tf":1.4142135623730951},"67":{"tf":1.0},"69":{"tf":1.0}},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"72":{"tf":1.0}}}},"s":{"_":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":0,"docs":{},"u":{"df":0,"docs":{},"m":{"df":1,"docs":{"54":{"tf":2.449489742783178}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"v":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"88":{"tf":1.0}}}}}},"df":2,"docs":{"17":{"tf":1.0},"26":{"tf":1.0}},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":15,"docs":{"17":{"tf":1.0},"2":{"tf":1.0},"37":{"tf":1.0},"49":{"tf":1.0},"5":{"tf":1.0},"58":{"tf":1.0},"6":{"tf":1.0},"61":{"tf":1.0},"62":{"tf":2.0},"63":{"tf":1.0},"65":{"tf":1.0},"66":{"tf":1.4142135623730951},"72":{"tf":1.0},"74":{"tf":1.0},"85":{"tf":1.0}}}}},"t":{"df":4,"docs":{"1":{"tf":1.0},"49":{"tf":1.0},"55":{"tf":1.0},"57":{"tf":1.4142135623730951}}}},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"74":{"tf":1.0}},"h":{"df":0,"docs":{},"u":{"b":{"df":1,"docs":{"60":{"tf":1.0}}},"df":0,"docs":{}}}},"v":{"df":0,"docs":{},"e":{"df":1,"docs":{"89":{"tf":1.0}},"n":{"df":3,"docs":{"62":{"tf":1.0},"65":{"tf":1.0},"89":{"tf":1.0}}}}}},"l":{"a":{"d":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"56":{"tf":1.0}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"o":{"d":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{".":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":1,"docs":{"22":{"tf":1.0}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":2,"docs":{"74":{"tf":1.4142135623730951},"76":{"tf":1.4142135623730951}},"e":{"df":1,"docs":{"74":{"tf":1.0}}},"o":{"d":{"df":2,"docs":{"58":{"tf":1.0},"63":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"r":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"52":{"tf":1.0}}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"49":{"tf":1.0}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"58":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"w":{"df":1,"docs":{"14":{"tf":1.0}}}}},"u":{"a":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":1,"docs":{"72":{"tf":1.0}}}}}},"df":0,"docs":{}}},"df":0,"docs":{},"i":{"d":{"df":73,"docs":{"1":{"tf":1.4142135623730951},"10":{"tf":1.0},"11":{"tf":1.0},"12":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"15":{"tf":1.0},"16":{"tf":1.0},"17":{"tf":1.0},"18":{"tf":1.0},"19":{"tf":1.0},"20":{"tf":1.0},"21":{"tf":1.0},"22":{"tf":1.0},"23":{"tf":1.0},"24":{"tf":1.0},"25":{"tf":1.0},"26":{"tf":1.0},"27":{"tf":1.0},"28":{"tf":1.0},"29":{"tf":1.0},"30":{"tf":1.0},"31":{"tf":1.0},"32":{"tf":1.0},"33":{"tf":1.0},"34":{"tf":1.0},"35":{"tf":1.0},"36":{"tf":1.0},"37":{"tf":1.0},"38":{"tf":1.0},"39":{"tf":1.0},"4":{"tf":1.7320508075688772},"40":{"tf":1.0},"41":{"tf":1.0},"42":{"tf":1.0},"43":{"tf":1.0},"44":{"tf":1.0},"45":{"tf":1.0},"46":{"tf":1.0},"47":{"tf":1.0},"48":{"tf":1.0},"49":{"tf":1.0},"5":{"tf":1.0},"55":{"tf":1.7320508075688772},"56":{"tf":2.0},"57":{"tf":1.4142135623730951},"58":{"tf":1.4142135623730951},"59":{"tf":1.4142135623730951},"6":{"tf":1.0},"60":{"tf":1.4142135623730951},"61":{"tf":2.0},"62":{"tf":1.4142135623730951},"63":{"tf":1.0},"64":{"tf":1.0},"65":{"tf":1.0},"66":{"tf":1.0},"67":{"tf":1.0},"68":{"tf":1.0},"69":{"tf":1.0},"7":{"tf":1.0},"70":{"tf":1.0},"71":{"tf":1.0},"72":{"tf":1.0},"73":{"tf":1.0},"74":{"tf":1.0},"75":{"tf":1.4142135623730951},"76":{"tf":1.0},"77":{"tf":1.0},"78":{"tf":1.0},"79":{"tf":1.0},"8":{"tf":1.0},"80":{"tf":1.0},"9":{"tf":1.0}}},"df":0,"docs":{}}}},"h":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"f":{"df":1,"docs":{"72":{"tf":1.0}}},"l":{"df":0,"docs":{},"u":{"c":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"62":{"tf":1.0}}}}},"df":0,"docs":{}}}},"n":{"d":{"df":1,"docs":{"72":{"tf":1.0}},"i":{"df":1,"docs":{"50":{"tf":1.0}}}},"df":0,"docs":{}},"p":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":2,"docs":{"18":{"tf":1.4142135623730951},"64":{"tf":1.0}}}}}},"r":{"d":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"21":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"w":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"72":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"s":{"df":0,"docs":{},"h":{"df":7,"docs":{"0":{"tf":1.0},"18":{"tf":1.0},"35":{"tf":1.0},"40":{"tf":2.0},"41":{"tf":1.0},"42":{"tf":1.0},"65":{"tf":1.0}},"m":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"65":{"tf":1.0}}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"e":{"a":{"d":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{},"p":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"z":{"df":1,"docs":{"14":{"tf":1.0}}}}}},"df":5,"docs":{"0":{"tf":1.0},"14":{"tf":2.6457513110645907},"27":{"tf":1.4142135623730951},"37":{"tf":1.0},"67":{"tf":2.23606797749979}}},"v":{"df":0,"docs":{},"i":{"df":1,"docs":{"63":{"tf":1.0}}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":1,"docs":{"0":{"tf":1.0}}}},"p":{"df":4,"docs":{"1":{"tf":1.0},"11":{"tf":1.7320508075688772},"51":{"tf":1.4142135623730951},"55":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"76":{"tf":1.0}}}}}},"n":{"c":{"df":1,"docs":{"67":{"tf":1.0}}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"e":{"df":4,"docs":{"48":{"tf":1.0},"62":{"tf":1.0},"71":{"tf":1.0},"85":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":4,"docs":{"4":{"tf":1.0},"63":{"tf":1.0},"76":{"tf":1.0},"88":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":3,"docs":{"31":{"tf":1.0},"61":{"tf":1.0},"75":{"tf":1.0}}}}}}}}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"66":{"tf":1.0}}}}}}},"o":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":1,"docs":{"62":{"tf":1.0}}}},"o":{"d":{"df":1,"docs":{"64":{"tf":1.0}}},"df":0,"docs":{}},"s":{"df":0,"docs":{},"t":{"df":2,"docs":{"73":{"tf":1.7320508075688772},"79":{"tf":1.0}}}}},"t":{"df":0,"docs":{},"t":{"df":0,"docs":{},"p":{"df":0,"docs":{},"s":{":":{"/":{"/":{"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"u":{"b":{".":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"/":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"u":{"df":0,"docs":{},"m":{"/":{"df":0,"docs":{},"g":{"df":0,"docs":{},"o":{"df":1,"docs":{"74":{"tf":1.0}}}}},"df":0,"docs":{}}}}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"u":{"b":{"df":1,"docs":{"73":{"tf":1.0}}},"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"n":{"df":1,"docs":{"62":{"tf":1.0}}}},"df":0,"docs":{}}}},"i":{".":{"df":1,"docs":{"18":{"tf":1.4142135623730951}}},"d":{"df":1,"docs":{"23":{"tf":1.7320508075688772}},"e":{"a":{"df":1,"docs":{"49":{"tf":1.0}},"l":{"df":1,"docs":{"72":{"tf":1.0}}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":2,"docs":{"65":{"tf":1.0},"77":{"tf":1.0}}}}}}}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"n":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":3,"docs":{"0":{"tf":1.0},"38":{"tf":1.0},"72":{"tf":1.4142135623730951}}}}}},"m":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":12,"docs":{"0":{"tf":1.4142135623730951},"4":{"tf":1.0},"49":{"tf":2.449489742783178},"59":{"tf":1.0},"6":{"tf":1.0},"66":{"tf":2.23606797749979},"69":{"tf":1.0},"72":{"tf":1.0},"74":{"tf":1.7320508075688772},"75":{"tf":1.0},"76":{"tf":1.7320508075688772},"77":{"tf":1.4142135623730951}}}}}}},"i":{"df":2,"docs":{"18":{"tf":1.0},"37":{"tf":1.0}}}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":3,"docs":{"1":{"tf":1.0},"61":{"tf":1.0},"62":{"tf":1.0}}}}},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"v":{"df":2,"docs":{"85":{"tf":1.0},"89":{"tf":1.0}}}}}}},"n":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":2,"docs":{"13":{"tf":1.0},"14":{"tf":1.0}}}}}}},"l":{"df":0,"docs":{},"u":{"d":{"df":7,"docs":{"13":{"tf":1.0},"14":{"tf":1.0},"16":{"tf":1.0},"4":{"tf":1.0},"49":{"tf":1.0},"52":{"tf":1.0},"59":{"tf":1.0}}},"df":0,"docs":{}}},"o":{"df":0,"docs":{},"m":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"18":{"tf":1.0}}}}}}}},"r":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"s":{"df":3,"docs":{"13":{"tf":1.7320508075688772},"14":{"tf":1.0},"86":{"tf":1.0}}}},"df":0,"docs":{}}}},"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"73":{"tf":1.0}}}}}}}},"u":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":2,"docs":{"49":{"tf":1.0},"72":{"tf":1.0}}}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"i":{"df":2,"docs":{"49":{"tf":1.0},"72":{"tf":1.0}}}},"df":0,"docs":{}}}}},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"14":{"tf":1.0}}}}}},"o":{"df":1,"docs":{"17":{"tf":1.4142135623730951}},"r":{"df":0,"docs":{},"m":{"df":3,"docs":{"17":{"tf":1.0},"2":{"tf":1.0},"26":{"tf":1.0}}}}},"r":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"u":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"5":{"tf":1.0}}}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"49":{"tf":1.0},"62":{"tf":1.0}},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"48":{"tf":1.4142135623730951}}}}}}},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":3,"docs":{"30":{"tf":1.0},"48":{"tf":1.7320508075688772},"73":{"tf":1.0}}}}},"k":{"df":0,"docs":{},"w":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":1,"docs":{"68":{"tf":1.0}}}}}},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":4,"docs":{"18":{"tf":2.23606797749979},"4":{"tf":1.0},"61":{"tf":1.0},"83":{"tf":1.7320508075688772}}}}},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"u":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"d":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"d":{"df":1,"docs":{"48":{"tf":1.7320508075688772}}},"df":0,"docs":{}}}}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}},"t":{"df":0,"docs":{},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"48":{"tf":1.7320508075688772}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}},"p":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"18":{"tf":1.0}}}}}},"df":3,"docs":{"18":{"tf":1.4142135623730951},"22":{"tf":1.0},"24":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"i":{"d":{"df":5,"docs":{"18":{"tf":1.0},"40":{"tf":1.0},"51":{"tf":1.0},"67":{"tf":1.0},"77":{"tf":1.0}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":1,"docs":{"52":{"tf":1.0}}}}}},"t":{"a":{"df":0,"docs":{},"l":{"df":9,"docs":{"10":{"tf":1.0},"51":{"tf":2.449489742783178},"58":{"tf":1.0},"6":{"tf":2.0},"7":{"tf":1.4142135623730951},"74":{"tf":1.0},"79":{"tf":1.4142135623730951},"8":{"tf":2.0},"9":{"tf":1.0}}},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":4,"docs":{"0":{"tf":1.0},"40":{"tf":1.0},"53":{"tf":1.7320508075688772},"76":{"tf":1.7320508075688772}}}}}},"df":0,"docs":{},"e":{"a":{"d":{"df":10,"docs":{"0":{"tf":1.4142135623730951},"14":{"tf":1.0},"18":{"tf":1.0},"32":{"tf":1.4142135623730951},"35":{"tf":1.0},"40":{"tf":1.4142135623730951},"50":{"tf":1.0},"61":{"tf":1.0},"65":{"tf":1.0},"76":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"u":{"c":{"df":0,"docs":{},"t":{"df":7,"docs":{"10":{"tf":1.0},"18":{"tf":1.0},"32":{"tf":1.0},"40":{"tf":1.0},"52":{"tf":1.0},"72":{"tf":1.0},"8":{"tf":1.0}}}},"df":0,"docs":{}}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"g":{"df":0,"docs":{},"r":{"df":7,"docs":{"20":{"tf":2.0},"21":{"tf":1.0},"22":{"tf":1.0},"23":{"tf":1.0},"49":{"tf":1.0},"74":{"tf":1.7320508075688772},"76":{"tf":2.23606797749979}}}},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"73":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"f":{"a":{"c":{"df":19,"docs":{"11":{"tf":1.0},"12":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"15":{"tf":1.0},"16":{"tf":1.0},"17":{"tf":1.0},"18":{"tf":1.0},"24":{"tf":2.0},"25":{"tf":1.0},"26":{"tf":1.0},"27":{"tf":1.0},"28":{"tf":1.0},"29":{"tf":1.0},"30":{"tf":1.0},"49":{"tf":1.0},"66":{"tf":1.0},"68":{"tf":1.7320508075688772},"73":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"m":{"df":0,"docs":{},"e":{"d":{"df":0,"docs":{},"i":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"16":{"tf":1.0}}}}},"df":2,"docs":{"63":{"tf":1.0},"64":{"tf":1.0}}}},"df":0,"docs":{}}},"n":{"df":4,"docs":{"48":{"tf":1.4142135623730951},"55":{"tf":1.0},"63":{"tf":1.4142135623730951},"65":{"tf":1.0}}},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"72":{"tf":1.4142135623730951}}}}}}}},"r":{"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"u":{"c":{"df":3,"docs":{"0":{"tf":1.4142135623730951},"1":{"tf":1.0},"49":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"u":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"61":{"tf":1.0}}}}}},"v":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"d":{"df":1,"docs":{"65":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"v":{"df":2,"docs":{"18":{"tf":1.0},"62":{"tf":1.4142135623730951}}}}}}},"r":{"df":7,"docs":{"16":{"tf":1.4142135623730951},"47":{"tf":2.0},"48":{"tf":1.0},"63":{"tf":1.4142135623730951},"64":{"tf":1.4142135623730951},"66":{"tf":1.0},"69":{"tf":1.0}}},"s":{"a":{"df":1,"docs":{"72":{"tf":1.0}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"’":{"df":0,"docs":{},"t":{"df":4,"docs":{"0":{"tf":1.0},"18":{"tf":1.0},"72":{"tf":1.0},"75":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"u":{"df":1,"docs":{"60":{"tf":1.0}}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":1,"docs":{"61":{"tf":1.0}}},"r":{"df":1,"docs":{"65":{"tf":1.0}}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"f":{"df":4,"docs":{"49":{"tf":1.0},"5":{"tf":1.0},"60":{"tf":1.0},"68":{"tf":1.0}}}}}},"’":{"d":{"df":1,"docs":{"48":{"tf":1.0}}},"df":6,"docs":{"18":{"tf":1.0},"19":{"tf":1.0},"49":{"tf":1.0},"50":{"tf":1.0},"52":{"tf":1.0},"87":{"tf":1.0}}}}},"j":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":2,"docs":{"4":{"tf":1.0},"72":{"tf":2.23606797749979}}}},"s":{"df":1,"docs":{"19":{"tf":1.7320508075688772}},"o":{"df":0,"docs":{},"n":{"df":8,"docs":{"18":{"tf":1.4142135623730951},"24":{"tf":2.0},"25":{"tf":1.0},"26":{"tf":1.0},"27":{"tf":1.0},"28":{"tf":1.0},"29":{"tf":1.0},"30":{"tf":1.0}}}}},"u":{"d":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"62":{"tf":1.0}}}}}}}}},"df":0,"docs":{}}},"k":{"b":{"df":1,"docs":{"54":{"tf":1.0}}},"df":0,"docs":{},"e":{"c":{"c":{"a":{"df":0,"docs":{},"k":{"2":{"5":{"6":{"df":1,"docs":{"35":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{},"e":{"df":0,"docs":{},"p":{"df":5,"docs":{"11":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"62":{"tf":1.0},"88":{"tf":1.0}}}},"p":{"df":0,"docs":{},"t":{"df":2,"docs":{"58":{"tf":1.0},"67":{"tf":1.0}}}},"y":{"df":1,"docs":{"76":{"tf":1.0}},"w":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"40":{"tf":1.0}}},"df":0,"docs":{}}}}}},"n":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":3,"docs":{"11":{"tf":1.0},"18":{"tf":1.0},"49":{"tf":1.0}},"l":{"df":0,"docs":{},"e":{"d":{"df":0,"docs":{},"g":{"df":1,"docs":{"69":{"tf":1.0}}}},"df":0,"docs":{}}},"n":{"df":1,"docs":{"18":{"tf":1.0}}}}}}},"l":{"a":{"c":{"df":0,"docs":{},"k":{"df":2,"docs":{"14":{"tf":1.0},"69":{"tf":1.0}}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"u":{"a":{"df":0,"docs":{},"g":{"df":4,"docs":{"22":{"tf":1.0},"49":{"tf":2.6457513110645907},"61":{"tf":1.0},"88":{"tf":1.0}}}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"g":{"df":2,"docs":{"62":{"tf":1.0},"77":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"37":{"tf":1.0},"86":{"tf":1.4142135623730951}}}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"85":{"tf":1.7320508075688772}}}}}},"u":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"h":{"df":1,"docs":{"73":{"tf":1.0}}}},"df":0,"docs":{}}},"y":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"69":{"tf":1.0}}}},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"37":{"tf":1.0}}}}}}},"df":0,"docs":{},"e":{"a":{"d":{"df":4,"docs":{"0":{"tf":1.0},"36":{"tf":1.0},"37":{"tf":1.0},"62":{"tf":1.0}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":1,"docs":{"58":{"tf":1.0}}}},"v":{"df":1,"docs":{"68":{"tf":1.0}}}},"df":1,"docs":{"69":{"tf":1.0}},"g":{"a":{"c":{"df":0,"docs":{},"i":{"df":1,"docs":{"48":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"72":{"tf":1.0}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":8,"docs":{"12":{"tf":2.23606797749979},"36":{"tf":1.0},"37":{"tf":1.0},"4":{"tf":1.0},"49":{"tf":1.7320508075688772},"52":{"tf":1.0},"63":{"tf":1.0},"76":{"tf":1.0}}}}},"x":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"66":{"tf":1.0}}}}}},"i":{"b":{"c":{"df":1,"docs":{"80":{"tf":1.4142135623730951}}},"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":9,"docs":{"18":{"tf":3.4641016151377544},"49":{"tf":2.449489742783178},"5":{"tf":1.0},"59":{"tf":1.0},"64":{"tf":1.0},"65":{"tf":1.0},"66":{"tf":2.0},"73":{"tf":1.0},"76":{"tf":1.7320508075688772}}}}},"df":0,"docs":{}}},"df":2,"docs":{"62":{"tf":1.0},"88":{"tf":1.0}},"f":{"df":0,"docs":{},"t":{"df":1,"docs":{"63":{"tf":1.0}}}},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":3,"docs":{"34":{"tf":1.0},"37":{"tf":1.0},"86":{"tf":1.0}}}}},"n":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"r":{"df":3,"docs":{"37":{"tf":1.0},"67":{"tf":1.0},"72":{"tf":1.0}}}},"df":11,"docs":{"11":{"tf":1.0},"12":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"15":{"tf":1.0},"16":{"tf":1.0},"17":{"tf":1.0},"18":{"tf":1.0},"19":{"tf":1.0},"30":{"tf":1.0},"61":{"tf":1.0}}},"k":{"a":{"df":0,"docs":{},"g":{"df":1,"docs":{"18":{"tf":1.0}}}},"df":5,"docs":{"18":{"tf":3.7416573867739413},"49":{"tf":1.0},"64":{"tf":1.0},"65":{"tf":1.4142135623730951},"78":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":4,"docs":{"18":{"tf":1.4142135623730951},"64":{"tf":1.0},"68":{"tf":1.0},"71":{"tf":1.0}}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"61":{"tf":1.0}}}}},"u":{"df":0,"docs":{},"x":{"df":2,"docs":{"7":{"tf":1.0},"78":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"36":{"tf":1.0}}}},"t":{"df":0,"docs":{},"t":{"df":0,"docs":{},"l":{"df":1,"docs":{"59":{"tf":1.0}}}}},"v":{"df":0,"docs":{},"e":{"df":3,"docs":{"32":{"tf":1.0},"59":{"tf":1.0},"72":{"tf":1.0}}}}},"l":{"d":{"df":3,"docs":{"64":{"tf":1.0},"68":{"tf":1.4142135623730951},"79":{"tf":1.0}}},"df":1,"docs":{"66":{"tf":1.0}},"m":{"df":1,"docs":{"62":{"tf":1.0}}},"v":{"df":0,"docs":{},"m":{"/":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":0,"docs":{},"s":{"c":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"/":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"79":{"tf":1.0}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}}}},"g":{"df":0,"docs":{},"n":{"df":0,"docs":{},"u":{"/":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"79":{"tf":1.0}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"y":{"df":0,"docs":{},"s":{"_":{"1":{"8":{"1":{"_":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"x":{"=":{"$":{"df":0,"docs":{},"{":{"df":0,"docs":{},"p":{"df":0,"docs":{},"w":{"d":{"df":0,"docs":{},"}":{"/":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"79":{"tf":1.0}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":13,"docs":{"12":{"tf":1.7320508075688772},"16":{"tf":1.0},"29":{"tf":1.0},"30":{"tf":1.0},"49":{"tf":1.0},"5":{"tf":1.0},"63":{"tf":1.4142135623730951},"64":{"tf":1.4142135623730951},"66":{"tf":2.449489742783178},"68":{"tf":2.6457513110645907},"69":{"tf":1.4142135623730951},"79":{"tf":3.0},"89":{"tf":1.0}}}}},"o":{"c":{"a":{"df":0,"docs":{},"l":{"df":4,"docs":{"13":{"tf":1.0},"50":{"tf":1.0},"58":{"tf":1.0},"60":{"tf":1.0}}},"t":{"df":1,"docs":{"59":{"tf":1.0}}}},"df":0,"docs":{},"k":{"df":1,"docs":{"59":{"tf":1.4142135623730951}}}},"df":0,"docs":{},"g":{"df":1,"docs":{"52":{"tf":2.449489742783178}},"i":{"c":{"df":4,"docs":{"49":{"tf":1.0},"66":{"tf":1.4142135623730951},"74":{"tf":1.0},"76":{"tf":1.0}}},"df":0,"docs":{}}},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"23":{"tf":1.0}}}}}},"o":{"df":0,"docs":{},"k":{"df":1,"docs":{"88":{"tf":1.0}}}},"s":{"df":0,"docs":{},"e":{"df":1,"docs":{"72":{"tf":1.0}}},"s":{"df":1,"docs":{"62":{"tf":1.0}}}},"t":{"df":2,"docs":{"76":{"tf":1.0},"77":{"tf":1.0}}},"w":{"df":5,"docs":{"36":{"tf":1.0},"37":{"tf":1.0},"49":{"tf":1.0},"52":{"tf":1.0},"88":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":4,"docs":{"49":{"tf":1.4142135623730951},"63":{"tf":1.0},"64":{"tf":1.4142135623730951},"66":{"tf":1.0}}}}}}},"m":{"a":{"c":{"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":2,"docs":{"13":{"tf":1.0},"69":{"tf":1.4142135623730951}}}}},"o":{"df":1,"docs":{"7":{"tf":1.0}}},"r":{"df":0,"docs":{},"o":{"df":1,"docs":{"61":{"tf":1.4142135623730951}}}}},"d":{"df":0,"docs":{},"e":{"df":1,"docs":{"60":{"tf":1.0}}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"61":{"tf":1.0}}},"df":0,"docs":{}},"n":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"d":{"df":1,"docs":{"72":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}}}},"i":{"df":0,"docs":{},"n":{"df":4,"docs":{"60":{"tf":1.0},"66":{"tf":1.0},"72":{"tf":1.0},"89":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":3,"docs":{"18":{"tf":1.0},"30":{"tf":1.0},"63":{"tf":1.0}}}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"m":{"df":1,"docs":{"49":{"tf":1.0}}}},"df":0,"docs":{}}}}},"t":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":7,"docs":{"23":{"tf":1.0},"57":{"tf":1.0},"60":{"tf":1.0},"62":{"tf":1.7320508075688772},"63":{"tf":1.0},"65":{"tf":1.0},"68":{"tf":1.0}}}}},"df":0,"docs":{}}}},"j":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":2,"docs":{"7":{"tf":1.0},"89":{"tf":1.4142135623730951}}}}},"k":{"df":0,"docs":{},"e":{"df":13,"docs":{"18":{"tf":1.4142135623730951},"19":{"tf":1.0},"3":{"tf":1.0},"40":{"tf":1.0},"49":{"tf":1.0},"51":{"tf":1.0},"58":{"tf":1.0},"60":{"tf":1.0},"61":{"tf":1.0},"65":{"tf":1.0},"67":{"tf":1.0},"74":{"tf":1.0},"79":{"tf":1.7320508075688772}},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"58":{"tf":1.7320508075688772}}}}}}},"n":{"a":{"df":0,"docs":{},"g":{"df":1,"docs":{"74":{"tf":1.0}}}},"df":0,"docs":{},"i":{"df":2,"docs":{"36":{"tf":1.0},"5":{"tf":1.4142135623730951}},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":1,"docs":{"88":{"tf":1.0}}}}}}}},"u":{"a":{"df":0,"docs":{},"l":{"df":2,"docs":{"40":{"tf":1.0},"76":{"tf":1.0}}}},"df":0,"docs":{}}},"p":{"df":1,"docs":{"72":{"tf":1.0}}},"t":{"c":{"df":0,"docs":{},"h":{"df":1,"docs":{"76":{"tf":1.0}}}},"df":0,"docs":{}},"x":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"u":{"df":0,"docs":{},"m":{"df":1,"docs":{"37":{"tf":1.0}}}}}}},"y":{"b":{"df":1,"docs":{"49":{"tf":1.0}}},"df":0,"docs":{}}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":1,"docs":{"37":{"tf":1.4142135623730951}}}}}},"d":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"k":{"df":1,"docs":{"3":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"n":{"df":2,"docs":{"37":{"tf":1.0},"61":{"tf":1.0}},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":1,"docs":{"61":{"tf":1.7320508075688772}}}}}},"s":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"65":{"tf":1.0}}}}}},"c":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"df":1,"docs":{"18":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":7,"docs":{"13":{"tf":1.7320508075688772},"14":{"tf":2.449489742783178},"27":{"tf":1.0},"36":{"tf":1.7320508075688772},"37":{"tf":3.0},"54":{"tf":1.0},"67":{"tf":2.0}}}}}},"r":{"df":0,"docs":{},"g":{"df":1,"docs":{"60":{"tf":1.0}}}},"s":{"df":0,"docs":{},"s":{"a":{"df":0,"docs":{},"g":{"df":2,"docs":{"11":{"tf":1.0},"61":{"tf":1.0}}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":3,"docs":{"0":{"tf":1.0},"14":{"tf":1.0},"67":{"tf":1.0}}}}}},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"c":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":1,"docs":{"62":{"tf":1.0}}}}},"df":0,"docs":{}}}},"s":{"df":0,"docs":{},"s":{"df":2,"docs":{"18":{"tf":1.4142135623730951},"69":{"tf":1.4142135623730951}}},"t":{"a":{"df":0,"docs":{},"k":{"df":1,"docs":{"62":{"tf":1.0}}}},"df":0,"docs":{}}},"x":{"df":1,"docs":{"49":{"tf":1.0}}}},"l":{"df":0,"docs":{},"o":{"a":{"d":{"df":1,"docs":{"37":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"df":0,"docs":{}}},"o":{"d":{"df":0,"docs":{},"e":{"df":2,"docs":{"18":{"tf":1.4142135623730951},"47":{"tf":1.4142135623730951}},"l":{"df":5,"docs":{"0":{"tf":1.0},"40":{"tf":1.4142135623730951},"46":{"tf":1.4142135623730951},"49":{"tf":1.0},"62":{"tf":1.0}}}},"u":{"df":0,"docs":{},"l":{"df":2,"docs":{"61":{"tf":1.0},"9":{"tf":1.0}}}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"69":{"tf":1.0}}}}}},"r":{"df":0,"docs":{},"e":{"df":9,"docs":{"11":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"2":{"tf":1.0},"5":{"tf":1.7320508075688772},"50":{"tf":1.0},"52":{"tf":1.0},"72":{"tf":1.4142135623730951},"77":{"tf":1.7320508075688772}}}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":3,"docs":{"24":{"tf":1.0},"72":{"tf":1.0},"89":{"tf":1.0}}}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":1,"docs":{"88":{"tf":1.0}}}}},"v":{"df":0,"docs":{},"e":{"df":1,"docs":{"72":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"z":{"df":0,"docs":{},"e":{"df":1,"docs":{"37":{"tf":1.7320508075688772}}}}},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":1,"docs":{"37":{"tf":1.4142135623730951}}}}}}},"u":{"c":{"df":0,"docs":{},"h":{"df":4,"docs":{"4":{"tf":1.0},"50":{"tf":1.0},"72":{"tf":1.0},"77":{"tf":1.4142135623730951}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":2,"docs":{"49":{"tf":1.0},"5":{"tf":1.0}}}}}}},"s":{"df":0,"docs":{},"l":{"df":4,"docs":{"68":{"tf":1.0},"7":{"tf":1.0},"78":{"tf":1.0},"80":{"tf":2.0}}}}}},"n":{"a":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":3,"docs":{"5":{"tf":1.4142135623730951},"59":{"tf":1.0},"61":{"tf":1.0}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":2,"docs":{"4":{"tf":1.0},"72":{"tf":1.4142135623730951}}}},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"49":{"tf":1.0}}}}}},"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"88":{"tf":1.0}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"e":{"d":{"df":8,"docs":{"18":{"tf":1.7320508075688772},"36":{"tf":1.0},"49":{"tf":1.0},"59":{"tf":1.4142135623730951},"61":{"tf":1.0},"68":{"tf":1.0},"72":{"tf":1.0},"88":{"tf":1.0}}},"df":0,"docs":{}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"18":{"tf":1.0},"76":{"tf":1.0}}}}},"w":{"df":3,"docs":{"40":{"tf":1.0},"59":{"tf":1.0},"74":{"tf":1.0}}}},"i":{"c":{"df":0,"docs":{},"e":{"df":1,"docs":{"19":{"tf":1.0}}}},"df":0,"docs":{}},"o":{"d":{"df":0,"docs":{},"e":{".":{"df":0,"docs":{},"j":{"df":3,"docs":{"19":{"tf":1.0},"78":{"tf":1.0},"9":{"tf":1.0}}}},"df":2,"docs":{"50":{"tf":1.4142135623730951},"77":{"tf":1.0}}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"5":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"n":{"df":6,"docs":{"18":{"tf":1.0},"59":{"tf":1.0},"61":{"tf":1.0},"65":{"tf":1.0},"67":{"tf":1.0},"68":{"tf":1.0}}},"t":{"a":{"b":{"df":0,"docs":{},"l":{"df":2,"docs":{"0":{"tf":1.0},"88":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"e":{"df":7,"docs":{"18":{"tf":1.4142135623730951},"19":{"tf":1.0},"36":{"tf":1.0},"49":{"tf":1.0},"71":{"tf":1.0},"72":{"tf":1.0},"76":{"tf":1.0}},"w":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"df":1,"docs":{"36":{"tf":1.0}}}}}}}}}}},"p":{"df":0,"docs":{},"m":{"df":2,"docs":{"19":{"tf":2.23606797749979},"9":{"tf":1.4142135623730951}}},"x":{"df":1,"docs":{"19":{"tf":1.0}}}},"u":{"a":{"df":0,"docs":{},"n":{"c":{"df":2,"docs":{"62":{"tf":1.0},"77":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"72":{"tf":1.0}}}}}}},"m":{"b":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"61":{"tf":1.0},"72":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"27":{"tf":1.4142135623730951}}}}},"t":{"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":2,"docs":{"40":{"tf":1.0},"50":{"tf":1.0}}}}}}}}},"o":{"(":{"df":0,"docs":{},"n":{"df":1,"docs":{"72":{"tf":1.0}}}},"b":{"df":0,"docs":{},"j":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":7,"docs":{"16":{"tf":1.0},"18":{"tf":1.0},"25":{"tf":1.4142135623730951},"27":{"tf":1.4142135623730951},"28":{"tf":1.7320508075688772},"64":{"tf":1.4142135623730951},"71":{"tf":1.0}}}},"df":0,"docs":{}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":4,"docs":{"0":{"tf":1.0},"3":{"tf":1.0},"31":{"tf":1.0},"76":{"tf":1.4142135623730951}}}}}},"t":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":2,"docs":{"78":{"tf":1.0},"79":{"tf":1.0}}}}},"df":0,"docs":{}},"v":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":1,"docs":{"61":{"tf":1.0}}}}}}},"df":3,"docs":{"12":{"tf":1.0},"19":{"tf":1.0},"29":{"tf":1.0}},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":3,"docs":{"4":{"tf":1.0},"46":{"tf":1.0},"67":{"tf":1.0}}}},"i":{"c":{"df":0,"docs":{},"i":{"df":3,"docs":{"18":{"tf":1.0},"61":{"tf":1.0},"65":{"tf":1.0}}}},"df":0,"docs":{}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":4,"docs":{"36":{"tf":1.4142135623730951},"37":{"tf":1.0},"38":{"tf":1.0},"54":{"tf":1.0}}}}}}},"k":{"(":{"0":{"df":1,"docs":{"54":{"tf":1.4142135623730951}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":1,"docs":{"54":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}}}}}}}}},"df":0,"docs":{}}}}},"df":1,"docs":{"54":{"tf":1.4142135623730951}}},"n":{"df":4,"docs":{"15":{"tf":1.0},"62":{"tf":1.0},"72":{"tf":1.0},"88":{"tf":1.0}},"w":{"a":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"82":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"p":{"c":{"df":0,"docs":{},"o":{"d":{"df":3,"docs":{"40":{"tf":1.0},"46":{"tf":1.0},"84":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":2,"docs":{"56":{"tf":1.0},"60":{"tf":1.0}}},"r":{"df":3,"docs":{"37":{"tf":1.0},"65":{"tf":1.0},"7":{"tf":1.0}}}},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":1,"docs":{"69":{"tf":1.4142135623730951}}}}}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":12,"docs":{"12":{"tf":3.4641016151377544},"16":{"tf":1.0},"18":{"tf":1.7320508075688772},"28":{"tf":1.0},"29":{"tf":1.0},"37":{"tf":1.0},"4":{"tf":1.0},"49":{"tf":1.0},"64":{"tf":1.0},"67":{"tf":1.0},"69":{"tf":2.449489742783178},"89":{"tf":1.4142135623730951}},"i":{"df":0,"docs":{},"z":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"63":{"tf":1.0}}}}}}},"o":{"df":0,"docs":{},"n":{"df":2,"docs":{"11":{"tf":1.4142135623730951},"19":{"tf":1.4142135623730951}}}}}}},"r":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"48":{"tf":1.4142135623730951},"72":{"tf":1.4142135623730951}}}}},"df":0,"docs":{},"g":{"a":{"df":0,"docs":{},"n":{"df":1,"docs":{"59":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"o":{"df":0,"docs":{},"g":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"69":{"tf":1.0}}}}}}}}},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"w":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":1,"docs":{"18":{"tf":1.0}}}}}}}}},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":2,"docs":{"31":{"tf":1.0},"36":{"tf":1.0}}}}},"t":{"_":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"54":{"tf":1.0}}}}}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"df":1,"docs":{"76":{"tf":1.4142135623730951}}}}},"d":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"23":{"tf":1.0}}}},"df":0,"docs":{}},"df":1,"docs":{"85":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"61":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"f":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"37":{"tf":1.0}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"g":{"a":{"df":1,"docs":{"36":{"tf":1.0}}},"df":0,"docs":{}}}},"p":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":3,"docs":{"16":{"tf":1.0},"17":{"tf":1.0},"52":{"tf":1.0}}}}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"r":{"c":{"df":0,"docs":{},"h":{"df":2,"docs":{"5":{"tf":1.0},"64":{"tf":1.0}}}},"df":0,"docs":{}}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"df":1,"docs":{"72":{"tf":1.0}}}}},"df":2,"docs":{"65":{"tf":1.0},"88":{"tf":1.0}},"f":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":1,"docs":{"67":{"tf":1.0}}}}}},"h":{"df":0,"docs":{},"e":{"a":{"d":{"df":1,"docs":{"72":{"tf":1.7320508075688772}}},"df":0,"docs":{}},"df":0,"docs":{}}},"r":{"df":0,"docs":{},"i":{"d":{"df":1,"docs":{"48":{"tf":1.0}}},"df":0,"docs":{}}},"v":{"df":0,"docs":{},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"df":1,"docs":{"89":{"tf":1.0}}}}}}}}},"z":{"df":1,"docs":{"12":{"tf":1.0}}}},"p":{"a":{"c":{"df":0,"docs":{},"k":{"a":{"df":0,"docs":{},"g":{"df":3,"docs":{"19":{"tf":2.23606797749979},"74":{"tf":1.0},"9":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"r":{"df":1,"docs":{"77":{"tf":1.0}}}},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":13,"docs":{"0":{"tf":1.7320508075688772},"31":{"tf":1.0},"34":{"tf":1.0},"38":{"tf":1.0},"43":{"tf":1.0},"50":{"tf":1.0},"52":{"tf":1.0},"70":{"tf":2.0},"71":{"tf":1.0},"72":{"tf":1.4142135623730951},"73":{"tf":2.23606797749979},"76":{"tf":1.4142135623730951},"77":{"tf":1.0}}}}}},"n":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"61":{"tf":1.0}}},"df":0,"docs":{}}},"r":{"a":{"c":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"88":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"61":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"21":{"tf":1.4142135623730951}}},"y":{"/":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"c":{"@":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"19":{"tf":1.0}}}}}}},"df":0,"docs":{}}},"df":1,"docs":{"19":{"tf":1.0}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"5":{"tf":1.0},"66":{"tf":1.4142135623730951}}}}},"t":{"df":1,"docs":{"59":{"tf":1.0}},"i":{"df":2,"docs":{"20":{"tf":1.0},"61":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"s":{"df":2,"docs":{"60":{"tf":1.4142135623730951},"72":{"tf":1.0}}}},"t":{"df":0,"docs":{},"h":{"=":{"/":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"/":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"/":{"df":0,"docs":{},"g":{"df":0,"docs":{},"o":{"df":1,"docs":{"74":{"tf":1.0}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":3,"docs":{"15":{"tf":1.4142135623730951},"61":{"tf":1.0},"74":{"tf":1.0}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":1,"docs":{"49":{"tf":1.0}}}}}}}},"c":{"df":1,"docs":{"45":{"tf":1.4142135623730951}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"m":{"df":3,"docs":{"12":{"tf":1.0},"63":{"tf":1.0},"85":{"tf":1.0}}}}}}}},"h":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"df":1,"docs":{"75":{"tf":1.0}}}}}}}}}}},"i":{"df":0,"docs":{},"e":{"c":{"df":1,"docs":{"49":{"tf":1.0}}},"df":0,"docs":{}},"n":{"df":1,"docs":{"59":{"tf":1.0}}},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":3,"docs":{"47":{"tf":1.0},"58":{"tf":1.0},"89":{"tf":1.0}}}}}}}},"l":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"m":{"df":4,"docs":{"65":{"tf":1.0},"68":{"tf":1.0},"7":{"tf":1.0},"88":{"tf":1.0}}}}}}}},"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"s":{"df":8,"docs":{"10":{"tf":1.0},"11":{"tf":1.0},"58":{"tf":1.0},"59":{"tf":1.7320508075688772},"61":{"tf":1.4142135623730951},"62":{"tf":1.0},"7":{"tf":1.0},"8":{"tf":1.0}}}},"df":0,"docs":{}}},"o":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"36":{"tf":1.4142135623730951},"40":{"tf":1.4142135623730951}}}}}}},"l":{"a":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{"df":1,"docs":{"4":{"tf":1.0}}}}},"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"i":{"df":1,"docs":{"62":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"k":{"a":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":6,"docs":{"2":{"tf":1.7320508075688772},"4":{"tf":1.0},"46":{"tf":1.0},"49":{"tf":1.0},"70":{"tf":1.0},"73":{"tf":1.0}}}}},"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{"df":7,"docs":{"1":{"tf":1.0},"5":{"tf":1.0},"52":{"tf":1.0},"6":{"tf":1.4142135623730951},"64":{"tf":1.4142135623730951},"70":{"tf":1.0},"79":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}}},"p":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"r":{"df":2,"docs":{"18":{"tf":1.0},"63":{"tf":1.0}}}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"t":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"19":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"62":{"tf":1.0}}}}}}},"s":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"b":{"df":0,"docs":{},"l":{"df":5,"docs":{"13":{"tf":1.0},"14":{"tf":1.0},"59":{"tf":1.4142135623730951},"75":{"tf":1.7320508075688772},"88":{"tf":1.0}}}},"df":0,"docs":{}}},"t":{"df":1,"docs":{"22":{"tf":1.0}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":3,"docs":{"0":{"tf":1.0},"31":{"tf":1.0},"65":{"tf":1.0}}}}}}},"w":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"63":{"tf":1.0},"77":{"tf":1.0}}}}}},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"c":{"df":2,"docs":{"49":{"tf":1.0},"72":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":3,"docs":{"59":{"tf":1.4142135623730951},"60":{"tf":1.7320508075688772},"62":{"tf":1.0}},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"59":{"tf":1.0}}}},"i":{"df":0,"docs":{},"x":{"df":1,"docs":{"59":{"tf":1.4142135623730951}}}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":2,"docs":{"37":{"tf":1.0},"75":{"tf":1.0}}}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":2,"docs":{"65":{"tf":1.0},"67":{"tf":1.0}}}}},"r":{"a":{"df":0,"docs":{},"n":{"d":{"a":{"df":0,"docs":{},"o":{"df":1,"docs":{"44":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"49":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"r":{"df":3,"docs":{"18":{"tf":1.0},"62":{"tf":1.0},"72":{"tf":1.0}},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"89":{"tf":1.0}}}}}}}},"o":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"62":{"tf":1.4142135623730951}}}},"df":1,"docs":{"72":{"tf":1.0}}}}}},"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":6,"docs":{"47":{"tf":1.0},"62":{"tf":1.0},"63":{"tf":1.0},"64":{"tf":1.0},"68":{"tf":1.0},"8":{"tf":1.0}}}}}},"d":{"df":0,"docs":{},"u":{"c":{"df":5,"docs":{"18":{"tf":1.0},"45":{"tf":1.0},"46":{"tf":1.0},"62":{"tf":1.0},"63":{"tf":1.0}},"t":{"df":1,"docs":{"18":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"85":{"tf":1.0}}}}},"g":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"m":{"df":2,"docs":{"49":{"tf":1.0},"88":{"tf":1.0}}}},"df":0,"docs":{}}},"j":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":6,"docs":{"3":{"tf":1.0},"5":{"tf":1.0},"56":{"tf":1.0},"62":{"tf":1.4142135623730951},"79":{"tf":1.0},"88":{"tf":1.0}},"’":{"df":2,"docs":{"57":{"tf":1.0},"89":{"tf":1.0}}}}},"df":0,"docs":{}}},"o":{"df":0,"docs":{},"f":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"z":{"df":1,"docs":{"54":{"tf":2.449489742783178}}}}}},"df":2,"docs":{"49":{"tf":1.0},"62":{"tf":1.0}}}},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"65":{"tf":1.0}}}}}}},"v":{"df":0,"docs":{},"e":{"df":1,"docs":{"76":{"tf":1.0}}},"i":{"d":{"df":8,"docs":{"18":{"tf":2.23606797749979},"49":{"tf":1.0},"53":{"tf":1.0},"61":{"tf":1.7320508075688772},"63":{"tf":1.0},"73":{"tf":1.0},"76":{"tf":1.4142135623730951},"88":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"x":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"72":{"tf":1.0}}}}}}},"u":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"c":{"df":2,"docs":{"48":{"tf":1.4142135623730951},"61":{"tf":1.0}}},"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"df":1,"docs":{"19":{"tf":1.0}}}}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":1,"docs":{"60":{"tf":1.4142135623730951}}}},"r":{"df":0,"docs":{},"g":{"a":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"=":{"6":{"1":{"4":{"4":{"/":{"3":{"1":{"4":{"5":{"7":{"2":{"8":{"df":1,"docs":{"54":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"s":{"df":5,"docs":{"16":{"tf":1.0},"17":{"tf":1.0},"30":{"tf":1.0},"49":{"tf":1.0},"72":{"tf":1.0}}}}}},"s":{"df":0,"docs":{},"h":{"df":1,"docs":{"60":{"tf":1.0}}}}},"v":{"df":0,"docs":{},"m":{"df":25,"docs":{"0":{"tf":1.4142135623730951},"13":{"tf":1.0},"14":{"tf":1.4142135623730951},"16":{"tf":1.0},"18":{"tf":1.0},"24":{"tf":1.0},"25":{"tf":1.0},"27":{"tf":1.0},"28":{"tf":1.0},"32":{"tf":1.0},"36":{"tf":1.0},"4":{"tf":1.4142135623730951},"45":{"tf":1.0},"49":{"tf":1.0},"52":{"tf":1.0},"67":{"tf":1.0},"68":{"tf":1.0},"69":{"tf":1.0},"70":{"tf":2.0},"71":{"tf":1.4142135623730951},"72":{"tf":3.0},"73":{"tf":1.0},"76":{"tf":1.4142135623730951},"88":{"tf":1.0},"89":{"tf":1.0}}}},"y":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"49":{"tf":1.0}}}}}}}},"q":{"df":0,"docs":{},"u":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"61":{"tf":1.0}}}},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"56":{"tf":1.0}}}}}}},"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"k":{"df":1,"docs":{"57":{"tf":1.0}}}},"df":0,"docs":{}}}},"r":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":1,"docs":{"18":{"tf":1.4142135623730951}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"62":{"tf":1.0}}}},"df":0,"docs":{}}}}},"w":{"df":1,"docs":{"18":{"tf":1.0}}}},"df":0,"docs":{},"e":{"a":{"d":{"a":{"b":{"df":0,"docs":{},"l":{"df":2,"docs":{"58":{"tf":1.0},"61":{"tf":1.0}}}},"df":0,"docs":{}},"df":5,"docs":{"1":{"tf":1.0},"31":{"tf":1.0},"37":{"tf":1.0},"58":{"tf":1.0},"62":{"tf":1.0}},"m":{"df":0,"docs":{},"e":{".":{"df":0,"docs":{},"m":{"d":{"df":2,"docs":{"10":{"tf":1.0},"57":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"z":{"df":2,"docs":{"69":{"tf":1.0},"88":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":6,"docs":{"18":{"tf":1.0},"40":{"tf":1.0},"49":{"tf":1.0},"66":{"tf":1.0},"67":{"tf":1.0},"88":{"tf":1.0}}}}}},"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":1,"docs":{"36":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"m":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"d":{"df":2,"docs":{"66":{"tf":1.0},"85":{"tf":1.0}}},"df":0,"docs":{}}}}}}},"d":{"df":0,"docs":{},"u":{"c":{"df":1,"docs":{"72":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"f":{"_":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"54":{"tf":2.449489742783178}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":7,"docs":{"36":{"tf":1.0},"4":{"tf":1.0},"57":{"tf":1.0},"6":{"tf":1.0},"75":{"tf":1.0},"76":{"tf":1.0},"8":{"tf":1.0}}}}},"g":{"a":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"47":{"tf":1.4142135623730951}},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"18":{"tf":1.0}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":2,"docs":{"13":{"tf":1.0},"72":{"tf":1.4142135623730951}}}}},"u":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"49":{"tf":1.0}}}},"df":0,"docs":{}},"r":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"62":{"tf":1.0}}}}}},"df":0,"docs":{}}}},"j":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"62":{"tf":1.0}}}},"df":0,"docs":{}}},"l":{"a":{"df":0,"docs":{},"t":{"df":3,"docs":{"24":{"tf":1.0},"37":{"tf":1.4142135623730951},"46":{"tf":1.4142135623730951}}}},"df":1,"docs":{"18":{"tf":1.0}},"e":{"a":{"df":0,"docs":{},"s":{"df":4,"docs":{"65":{"tf":1.4142135623730951},"68":{"tf":1.4142135623730951},"7":{"tf":1.7320508075688772},"89":{"tf":1.7320508075688772}}}},"df":0,"docs":{}},"i":{"df":2,"docs":{"63":{"tf":1.0},"89":{"tf":1.0}}},"o":{"c":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"71":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"x":{".":{"df":0,"docs":{},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"k":{"a":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{".":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":1,"docs":{"23":{"tf":1.0}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":1,"docs":{"23":{"tf":1.7320508075688772}}}},"o":{"df":0,"docs":{},"v":{"df":3,"docs":{"46":{"tf":1.0},"72":{"tf":1.0},"76":{"tf":1.0}}}}},"p":{"df":0,"docs":{},"l":{"a":{"c":{"df":1,"docs":{"87":{"tf":1.7320508075688772}}},"df":0,"docs":{}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":1,"docs":{"77":{"tf":1.0}}}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":2,"docs":{"51":{"tf":1.0},"60":{"tf":1.0}}}}}}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":1,"docs":{"49":{"tf":1.0}},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":2,"docs":{"63":{"tf":1.0},"64":{"tf":1.0}}}}}}},"o":{"d":{"df":0,"docs":{},"u":{"c":{"df":1,"docs":{"65":{"tf":2.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"q":{"df":0,"docs":{},"u":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":2,"docs":{"18":{"tf":1.0},"60":{"tf":1.7320508075688772}}}}},"i":{"df":0,"docs":{},"r":{"df":11,"docs":{"18":{"tf":1.0},"50":{"tf":1.0},"51":{"tf":1.0},"6":{"tf":1.0},"61":{"tf":1.0},"62":{"tf":1.0},"68":{"tf":1.0},"71":{"tf":1.0},"72":{"tf":1.0},"74":{"tf":1.0},"79":{"tf":1.0}}}}}},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"c":{".":{"df":0,"docs":{},"j":{"df":1,"docs":{"78":{"tf":1.0}}}},"df":54,"docs":{"10":{"tf":1.7320508075688772},"11":{"tf":2.0},"12":{"tf":1.4142135623730951},"13":{"tf":1.0},"14":{"tf":1.0},"15":{"tf":1.0},"16":{"tf":1.0},"17":{"tf":1.0},"18":{"tf":2.23606797749979},"19":{"tf":1.4142135623730951},"20":{"tf":1.4142135623730951},"21":{"tf":1.4142135623730951},"22":{"tf":1.4142135623730951},"23":{"tf":1.7320508075688772},"24":{"tf":1.0},"25":{"tf":1.0},"26":{"tf":1.4142135623730951},"27":{"tf":1.7320508075688772},"28":{"tf":1.0},"29":{"tf":1.4142135623730951},"30":{"tf":1.0},"31":{"tf":1.0},"32":{"tf":1.0},"33":{"tf":1.0},"34":{"tf":1.0},"35":{"tf":1.0},"36":{"tf":1.0},"37":{"tf":1.0},"38":{"tf":1.0},"39":{"tf":1.0},"4":{"tf":2.449489742783178},"40":{"tf":1.0},"41":{"tf":1.0},"42":{"tf":1.0},"43":{"tf":1.0},"44":{"tf":1.0},"45":{"tf":1.0},"46":{"tf":1.0},"47":{"tf":1.4142135623730951},"48":{"tf":1.0},"49":{"tf":1.0},"5":{"tf":2.449489742783178},"58":{"tf":1.4142135623730951},"6":{"tf":1.4142135623730951},"64":{"tf":2.0},"65":{"tf":1.4142135623730951},"68":{"tf":1.0},"7":{"tf":2.0},"79":{"tf":1.0},"8":{"tf":1.4142135623730951},"85":{"tf":1.0},"87":{"tf":1.7320508075688772},"89":{"tf":1.0},"9":{"tf":1.0}}},"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"18":{"tf":1.0}}}},"v":{"df":1,"docs":{"18":{"tf":1.0}}}},"u":{"df":0,"docs":{},"r":{"c":{"df":1,"docs":{"2":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"t":{"df":3,"docs":{"38":{"tf":1.0},"43":{"tf":1.0},"86":{"tf":1.0}}}},"df":0,"docs":{}}}},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":2,"docs":{"66":{"tf":1.0},"76":{"tf":1.7320508075688772}}}}}},"t":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"88":{"tf":1.0}}}}},"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"d":{"a":{"df":0,"docs":{},"t":{"a":{"df":1,"docs":{"43":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":7,"docs":{"32":{"tf":1.0},"35":{"tf":1.0},"38":{"tf":1.0},"41":{"tf":1.0},"42":{"tf":1.0},"43":{"tf":1.4142135623730951},"48":{"tf":2.449489742783178}}}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":4,"docs":{"13":{"tf":1.0},"14":{"tf":1.0},"43":{"tf":1.4142135623730951},"54":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"df":1,"docs":{"62":{"tf":1.0}}}},"v":{"df":38,"docs":{"0":{"tf":1.7320508075688772},"10":{"tf":1.0},"24":{"tf":1.0},"3":{"tf":1.0},"31":{"tf":1.0},"34":{"tf":1.0},"37":{"tf":1.0},"38":{"tf":1.0},"40":{"tf":2.23606797749979},"43":{"tf":1.0},"47":{"tf":1.0},"49":{"tf":1.0},"5":{"tf":2.23606797749979},"50":{"tf":2.23606797749979},"51":{"tf":2.0},"52":{"tf":1.7320508075688772},"53":{"tf":1.4142135623730951},"54":{"tf":1.4142135623730951},"55":{"tf":1.0},"56":{"tf":1.0},"59":{"tf":1.4142135623730951},"6":{"tf":1.0},"62":{"tf":1.0},"63":{"tf":1.4142135623730951},"64":{"tf":1.0},"65":{"tf":1.0},"66":{"tf":2.449489742783178},"68":{"tf":1.0},"70":{"tf":2.23606797749979},"71":{"tf":1.0},"72":{"tf":1.4142135623730951},"73":{"tf":2.6457513110645907},"74":{"tf":1.0},"76":{"tf":2.8284271247461903},"77":{"tf":1.7320508075688772},"79":{"tf":1.7320508075688772},"88":{"tf":1.4142135623730951},"9":{"tf":1.7320508075688772}},"e":{"_":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{"_":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"x":{"=":{"$":{"df":0,"docs":{},"{":{"df":0,"docs":{},"p":{"df":0,"docs":{},"w":{"d":{"df":0,"docs":{},"}":{"/":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"79":{"tf":1.0}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":1,"docs":{"79":{"tf":1.0}}}}}}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"88":{"tf":1.0}}}}}}},"w":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"88":{"tf":1.0}}}}}}},"i":{"df":0,"docs":{},"s":{"c":{"df":5,"docs":{"49":{"tf":1.0},"63":{"tf":1.0},"64":{"tf":1.0},"69":{"tf":1.0},"72":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"o":{"a":{"d":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"p":{"df":3,"docs":{"49":{"tf":1.0},"88":{"tf":1.7320508075688772},"89":{"tf":2.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":0,"docs":{},"p":{"df":1,"docs":{"46":{"tf":1.4142135623730951}}}}}},"o":{"df":0,"docs":{},"m":{"df":1,"docs":{"76":{"tf":1.0}}},"t":{"df":1,"docs":{"51":{"tf":1.0}}}},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":1,"docs":{"89":{"tf":1.0}}}}}},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":4,"docs":{"0":{"tf":1.0},"34":{"tf":1.7320508075688772},"58":{"tf":1.0},"60":{"tf":1.4142135623730951}}}},"n":{"df":10,"docs":{"0":{"tf":1.0},"3":{"tf":1.0},"48":{"tf":1.0},"50":{"tf":1.4142135623730951},"53":{"tf":1.0},"58":{"tf":1.4142135623730951},"59":{"tf":1.0},"74":{"tf":1.0},"78":{"tf":1.0},"85":{"tf":1.0}},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":7,"docs":{"50":{"tf":2.0},"51":{"tf":1.7320508075688772},"52":{"tf":1.0},"53":{"tf":1.4142135623730951},"54":{"tf":1.4142135623730951},"76":{"tf":2.449489742783178},"77":{"tf":1.4142135623730951}}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":14,"docs":{"0":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"32":{"tf":2.23606797749979},"37":{"tf":1.0},"40":{"tf":1.4142135623730951},"50":{"tf":1.0},"52":{"tf":1.4142135623730951},"70":{"tf":1.7320508075688772},"71":{"tf":1.0},"72":{"tf":1.0},"73":{"tf":2.0},"76":{"tf":1.0},"77":{"tf":1.0}},"e":{":":{":":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":1,"docs":{"54":{"tf":1.7320508075688772}},"i":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{":":{":":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"c":{"df":1,"docs":{"54":{"tf":2.449489742783178}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"s":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"g":{"=":{"df":0,"docs":{},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"k":{"a":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{"=":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"c":{"df":1,"docs":{"52":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}},"r":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"=":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"c":{"df":2,"docs":{"52":{"tf":1.0},"54":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}}}},"df":1,"docs":{"52":{"tf":1.0}}}}}},"df":7,"docs":{"49":{"tf":3.1622776601683795},"51":{"tf":1.0},"59":{"tf":1.7320508075688772},"61":{"tf":1.0},"68":{"tf":1.0},"80":{"tf":1.4142135623730951},"88":{"tf":1.0}}}}},"v":{"6":{"4":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"a":{"c":{"b":{"df":1,"docs":{"68":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"s":{"a":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":2,"docs":{"49":{"tf":1.0},"89":{"tf":1.0}}}},"m":{"df":0,"docs":{},"e":{"df":7,"docs":{"18":{"tf":1.4142135623730951},"49":{"tf":1.0},"61":{"tf":1.0},"65":{"tf":1.0},"72":{"tf":1.0},"77":{"tf":1.0},"84":{"tf":1.0}}}},"n":{"d":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"x":{"df":7,"docs":{"50":{"tf":1.7320508075688772},"51":{"tf":1.0},"52":{"tf":1.0},"53":{"tf":1.0},"54":{"tf":1.0},"72":{"tf":1.0},"76":{"tf":1.0}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"v":{"df":0,"docs":{},"e":{"df":1,"docs":{"40":{"tf":1.0}}}}},"c":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":1,"docs":{"88":{"tf":1.4142135623730951}}}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":3,"docs":{"49":{"tf":1.0},"68":{"tf":1.0},"79":{"tf":1.0}}}}}}},"d":{"df":0,"docs":{},"k":{"df":1,"docs":{"49":{"tf":1.4142135623730951}}}},"df":1,"docs":{"12":{"tf":1.0}},"e":{"a":{"df":0,"docs":{},"l":{"_":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"(":{"df":0,"docs":{},"f":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"g":{"df":1,"docs":{"54":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}},"m":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"49":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"40":{"tf":1.0}}}}}}}}}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"89":{"tf":1.0}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":2,"docs":{"0":{"tf":1.0},"31":{"tf":1.4142135623730951}}}}}},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"62":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"d":{"df":1,"docs":{"72":{"tf":1.0}}},"df":8,"docs":{"11":{"tf":1.0},"22":{"tf":1.0},"37":{"tf":1.0},"49":{"tf":1.0},"51":{"tf":1.0},"66":{"tf":1.0},"83":{"tf":1.0},"84":{"tf":1.0}}},"m":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":5,"docs":{"0":{"tf":1.0},"61":{"tf":1.0},"69":{"tf":1.0},"75":{"tf":1.0},"76":{"tf":1.0}}}}},"df":0,"docs":{}},"n":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"62":{"tf":1.0}}}}},"t":{"df":1,"docs":{"77":{"tf":1.0}}}},"t":{"df":8,"docs":{"12":{"tf":1.0},"18":{"tf":1.0},"25":{"tf":1.0},"27":{"tf":1.0},"28":{"tf":1.0},"29":{"tf":1.0},"67":{"tf":1.0},"76":{"tf":1.4142135623730951}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"s":{".":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"u":{"df":1,"docs":{"30":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}}}}},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"28":{"tf":1.7320508075688772}},"i":{"df":0,"docs":{},"z":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{".":{"df":0,"docs":{},"m":{"df":0,"docs":{},"o":{"d":{"df":1,"docs":{"29":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}}}}},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"k":{"a":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{".":{"d":{"df":0,"docs":{},"e":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"m":{"df":1,"docs":{"26":{"tf":1.4142135623730951}}}}}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"y":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":1,"docs":{"27":{"tf":1.4142135623730951}}}}},"i":{"df":0,"docs":{},"f":{"df":0,"docs":{},"g":{".":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"s":{"df":1,"docs":{"27":{"tf":1.0}}}}},"df":0,"docs":{}}},"s":{"df":0,"docs":{},"t":{"a":{"c":{"df":0,"docs":{},"k":{"df":0,"docs":{},"s":{"df":1,"docs":{"27":{"tf":1.0}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}}}}}},"df":1,"docs":{"25":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}}}}}},"h":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":1,"docs":{"64":{"tf":1.4142135623730951}}}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":1,"docs":{"72":{"tf":1.0}}}},"w":{"df":2,"docs":{"62":{"tf":1.0},"72":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"n":{"df":1,"docs":{"62":{"tf":1.0}},"i":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"c":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":2,"docs":{"88":{"tf":1.0},"89":{"tf":1.0}}}}}}},"df":2,"docs":{"69":{"tf":1.0},"88":{"tf":1.0}}},"df":0,"docs":{}}}}}},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"r":{"df":3,"docs":{"18":{"tf":1.0},"67":{"tf":1.0},"72":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"87":{"tf":1.0}}}}}},"df":0,"docs":{}}},"p":{"df":0,"docs":{},"l":{"df":4,"docs":{"18":{"tf":1.0},"66":{"tf":1.0},"74":{"tf":1.0},"76":{"tf":1.0}},"i":{"df":1,"docs":{"76":{"tf":1.0}},"f":{"df":0,"docs":{},"i":{"df":2,"docs":{"18":{"tf":1.0},"76":{"tf":1.0}}}}}}}},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"l":{"df":6,"docs":{"29":{"tf":1.0},"32":{"tf":1.0},"5":{"tf":1.4142135623730951},"50":{"tf":1.0},"72":{"tf":1.0},"88":{"tf":1.0}}}}},"t":{"df":1,"docs":{"72":{"tf":1.0}}},"z":{"df":0,"docs":{},"e":{"df":15,"docs":{"0":{"tf":1.4142135623730951},"12":{"tf":1.7320508075688772},"13":{"tf":2.6457513110645907},"14":{"tf":2.6457513110645907},"27":{"tf":2.0},"32":{"tf":1.4142135623730951},"36":{"tf":1.7320508075688772},"37":{"tf":1.0},"38":{"tf":1.0},"40":{"tf":1.0},"42":{"tf":1.0},"43":{"tf":1.0},"67":{"tf":1.4142135623730951},"86":{"tf":1.7320508075688772},"89":{"tf":1.0}}}}},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":1,"docs":{"62":{"tf":1.4142135623730951}}},"w":{"df":1,"docs":{"72":{"tf":1.7320508075688772}},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"72":{"tf":1.0}}}}}}},"m":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":4,"docs":{"13":{"tf":1.0},"14":{"tf":1.0},"47":{"tf":1.0},"49":{"tf":1.0}}}},"r":{"df":0,"docs":{},"t":{"df":3,"docs":{"4":{"tf":1.0},"63":{"tf":1.0},"72":{"tf":1.0}}}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"f":{"df":0,"docs":{},"t":{"df":0,"docs":{},"w":{"a":{"df":0,"docs":{},"r":{"df":3,"docs":{"49":{"tf":1.0},"56":{"tf":1.0},"62":{"tf":1.0}}}},"df":0,"docs":{}}}},"l":{"c":{"df":18,"docs":{"11":{"tf":1.0},"15":{"tf":2.23606797749979},"18":{"tf":2.23606797749979},"24":{"tf":1.0},"36":{"tf":1.0},"47":{"tf":2.0},"6":{"tf":1.0},"63":{"tf":1.4142135623730951},"64":{"tf":1.0},"65":{"tf":1.4142135623730951},"69":{"tf":1.4142135623730951},"75":{"tf":1.0},"76":{"tf":1.0},"8":{"tf":1.7320508075688772},"82":{"tf":1.0},"85":{"tf":1.0},"87":{"tf":1.7320508075688772},"89":{"tf":1.0}}},"df":0,"docs":{},"e":{"df":1,"docs":{"62":{"tf":1.0}}},"i":{"d":{"df":25,"docs":{"0":{"tf":1.4142135623730951},"1":{"tf":1.4142135623730951},"18":{"tf":2.23606797749979},"21":{"tf":1.7320508075688772},"22":{"tf":1.0},"3":{"tf":1.0},"31":{"tf":1.4142135623730951},"33":{"tf":1.7320508075688772},"36":{"tf":1.0},"4":{"tf":2.0},"40":{"tf":1.0},"49":{"tf":1.7320508075688772},"5":{"tf":1.0},"57":{"tf":1.0},"6":{"tf":1.7320508075688772},"62":{"tf":1.0},"63":{"tf":1.7320508075688772},"64":{"tf":1.4142135623730951},"75":{"tf":2.0},"76":{"tf":1.7320508075688772},"8":{"tf":1.0},"82":{"tf":1.0},"85":{"tf":1.4142135623730951},"88":{"tf":2.0},"89":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"49":{"tf":1.0}}}}},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"49":{"tf":1.0}}},"i":{"df":0,"docs":{},"m":{"df":3,"docs":{"50":{"tf":1.0},"52":{"tf":1.0},"59":{"tf":1.0}}}}},"w":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"72":{"tf":1.0}}}}}}}},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"62":{"tf":1.0}}}}}}},"r":{"c":{"df":9,"docs":{"10":{"tf":1.4142135623730951},"17":{"tf":1.0},"18":{"tf":1.0},"51":{"tf":1.0},"56":{"tf":1.0},"64":{"tf":1.4142135623730951},"74":{"tf":1.0},"79":{"tf":1.0},"89":{"tf":1.0}}},"df":0,"docs":{}}}},"p":{"a":{"c":{"df":0,"docs":{},"e":{"df":1,"docs":{"13":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"df":0,"docs":{},"e":{"c":{"df":2,"docs":{"76":{"tf":1.4142135623730951},"77":{"tf":1.4142135623730951}},"i":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"68":{"tf":1.0}}}},"df":0,"docs":{},"f":{"df":8,"docs":{"25":{"tf":1.0},"27":{"tf":1.0},"28":{"tf":1.0},"49":{"tf":1.0},"68":{"tf":1.0},"69":{"tf":1.0},"72":{"tf":1.0},"76":{"tf":1.4142135623730951}},"i":{"df":3,"docs":{"15":{"tf":1.0},"16":{"tf":1.0},"30":{"tf":1.0}}}}}},"df":0,"docs":{},"e":{"d":{"df":3,"docs":{"1":{"tf":1.0},"72":{"tf":1.4142135623730951},"88":{"tf":1.0}}},"df":0,"docs":{}}}},"r":{"c":{"/":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"/":{"b":{"a":{"df":0,"docs":{},"r":{".":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{":":{"b":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"18":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":1,"docs":{"18":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"t":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"73":{"tf":1.0}}}},"c":{"df":0,"docs":{},"k":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"z":{"df":1,"docs":{"13":{"tf":1.0}}}}}},"df":6,"docs":{"0":{"tf":1.0},"13":{"tf":2.8284271247461903},"27":{"tf":1.4142135623730951},"69":{"tf":1.0},"75":{"tf":1.0},"76":{"tf":1.0}}}},"df":0,"docs":{},"n":{"d":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"76":{"tf":1.0}}}}},"r":{"d":{"df":10,"docs":{"24":{"tf":2.0},"25":{"tf":1.0},"26":{"tf":1.0},"27":{"tf":1.0},"28":{"tf":1.0},"29":{"tf":1.0},"30":{"tf":1.0},"52":{"tf":1.0},"59":{"tf":1.0},"65":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"_":{"df":0,"docs":{},"i":{"d":{"df":1,"docs":{"48":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}}},"df":4,"docs":{"55":{"tf":1.0},"57":{"tf":1.4142135623730951},"69":{"tf":1.0},"82":{"tf":1.0}},"u":{"df":0,"docs":{},"p":{"df":3,"docs":{"13":{"tf":1.0},"14":{"tf":1.0},"72":{"tf":1.0}}}}}},"t":{"df":0,"docs":{},"e":{"df":5,"docs":{"48":{"tf":1.7320508075688772},"53":{"tf":1.0},"65":{"tf":1.0},"72":{"tf":1.0},"76":{"tf":1.4142135623730951}}},"i":{"c":{"df":4,"docs":{"14":{"tf":1.0},"65":{"tf":1.0},"67":{"tf":1.4142135623730951},"78":{"tf":1.0}}},"df":0,"docs":{}}}},"d":{"df":1,"docs":{"18":{"tf":1.4142135623730951}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"p":{"df":2,"docs":{"64":{"tf":1.0},"76":{"tf":1.0}}}},"i":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":1,"docs":{"18":{"tf":1.0}}}}},"o":{"c":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"62":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"g":{"df":1,"docs":{"76":{"tf":1.0}}}},"df":0,"docs":{}}},"r":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":1,"docs":{"62":{"tf":1.0}},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"w":{"a":{"df":0,"docs":{},"r":{"d":{"df":2,"docs":{"7":{"tf":1.0},"80":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"df":4,"docs":{"74":{"tf":2.0},"75":{"tf":1.0},"76":{"tf":1.0},"77":{"tf":1.7320508075688772}}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"49":{"tf":1.0}}}}}}},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":2,"docs":{"18":{"tf":1.0},"61":{"tf":1.0}}}},"p":{"df":1,"docs":{"50":{"tf":1.0}}}},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":3,"docs":{"34":{"tf":1.0},"40":{"tf":1.0},"66":{"tf":1.0}}}}}}},"u":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"18":{"tf":1.0}}}}}},"df":0,"docs":{}}},"u":{"d":{"df":0,"docs":{},"i":{"df":1,"docs":{"0":{"tf":1.0}}}},"df":0,"docs":{}},"y":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":2,"docs":{"61":{"tf":1.4142135623730951},"62":{"tf":1.0}}}}}},"u":{"b":{"df":0,"docs":{},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":2,"docs":{"60":{"tf":1.4142135623730951},"62":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"18":{"tf":1.0}}}}}}}}},"c":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"20":{"tf":1.0}},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"72":{"tf":1.0}}}}}}}},"df":0,"docs":{},"h":{"df":2,"docs":{"49":{"tf":1.0},"61":{"tf":1.0}}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"i":{"df":2,"docs":{"18":{"tf":1.0},"62":{"tf":1.0}}}},"df":0,"docs":{}}}},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"77":{"tf":1.0}}}},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"46":{"tf":1.0}}}}}}},"p":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":4,"docs":{"18":{"tf":1.0},"34":{"tf":1.0},"36":{"tf":1.0},"40":{"tf":1.4142135623730951}}}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":15,"docs":{"18":{"tf":1.0},"21":{"tf":1.0},"23":{"tf":1.0},"28":{"tf":1.0},"37":{"tf":1.0},"39":{"tf":1.0},"4":{"tf":1.0},"49":{"tf":1.4142135623730951},"65":{"tf":1.0},"7":{"tf":1.0},"79":{"tf":1.4142135623730951},"82":{"tf":2.0},"83":{"tf":1.7320508075688772},"84":{"tf":1.4142135623730951},"85":{"tf":1.7320508075688772}}}},"s":{"df":2,"docs":{"18":{"tf":1.0},"54":{"tf":1.0}}}}}},"r":{"df":0,"docs":{},"e":{"df":1,"docs":{"18":{"tf":1.0}}}}},"w":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"77":{"tf":1.0}}}},"df":0,"docs":{}},"y":{"df":1,"docs":{"68":{"tf":1.0}},"m":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":2,"docs":{"18":{"tf":1.4142135623730951},"61":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}},"s":{"c":{"a":{"df":0,"docs":{},"l":{"df":2,"docs":{"54":{"tf":1.0},"73":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":1,"docs":{"7":{"tf":1.0}}}}}}}},"t":{"a":{"df":0,"docs":{},"k":{"df":0,"docs":{},"e":{"df":3,"docs":{"18":{"tf":1.0},"63":{"tf":1.0},"77":{"tf":1.0}}}},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":12,"docs":{"1":{"tf":1.4142135623730951},"4":{"tf":1.0},"65":{"tf":1.0},"68":{"tf":1.4142135623730951},"69":{"tf":1.7320508075688772},"70":{"tf":2.0},"71":{"tf":2.0},"72":{"tf":1.4142135623730951},"73":{"tf":1.4142135623730951},"75":{"tf":1.0},"78":{"tf":1.0},"79":{"tf":2.23606797749979}}}}}}},"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"h":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"49":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"m":{"df":1,"docs":{"63":{"tf":1.0}},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"g":{"df":1,"docs":{"32":{"tf":1.0}}}}}}}}}},"s":{"df":0,"docs":{},"t":{"df":8,"docs":{"48":{"tf":1.4142135623730951},"58":{"tf":1.4142135623730951},"60":{"tf":1.0},"74":{"tf":3.0},"75":{"tf":1.0},"76":{"tf":3.7416573867739413},"77":{"tf":3.3166247903554},"79":{"tf":1.0}}}}},"h":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"k":{"df":2,"docs":{"4":{"tf":1.0},"77":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":2,"docs":{"32":{"tf":1.0},"37":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"59":{"tf":1.0}}}},"’":{"df":1,"docs":{"0":{"tf":1.0}}}}}},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":5,"docs":{"11":{"tf":1.0},"18":{"tf":1.0},"5":{"tf":1.0},"59":{"tf":1.0},"61":{"tf":1.4142135623730951}}}},"r":{"d":{"df":2,"docs":{"20":{"tf":1.0},"61":{"tf":1.0}}},"df":0,"docs":{}}},"o":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":2,"docs":{"11":{"tf":1.0},"18":{"tf":1.0}}}},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":1,"docs":{"69":{"tf":1.0}}}}}},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":2,"docs":{"64":{"tf":1.0},"76":{"tf":1.0}}}}}}},"u":{"df":5,"docs":{"18":{"tf":1.0},"37":{"tf":1.0},"40":{"tf":1.0},"69":{"tf":1.0},"77":{"tf":1.0}},"m":{"b":{"df":1,"docs":{"58":{"tf":1.0}}},"df":0,"docs":{}}}},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"49":{"tf":1.0}}}}}}},"m":{"df":0,"docs":{},"e":{"df":7,"docs":{"12":{"tf":1.7320508075688772},"18":{"tf":3.0},"38":{"tf":1.0},"43":{"tf":1.0},"45":{"tf":1.0},"46":{"tf":1.0},"72":{"tf":1.4142135623730951}},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"89":{"tf":1.0}}}}}}},"n":{"df":0,"docs":{},"i":{"df":1,"docs":{"77":{"tf":1.0}}}},"p":{"df":3,"docs":{"11":{"tf":1.0},"32":{"tf":1.0},"74":{"tf":1.0}}}},"m":{"df":0,"docs":{},"p":{"/":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"19":{"tf":1.0}}}}}},"df":0,"docs":{}}},"o":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":2,"docs":{"59":{"tf":1.0},"74":{"tf":1.0}}}}}},"o":{"df":0,"docs":{},"l":{"df":10,"docs":{"18":{"tf":1.0},"20":{"tf":2.0},"21":{"tf":1.0},"22":{"tf":1.0},"23":{"tf":1.0},"49":{"tf":1.0},"62":{"tf":1.0},"74":{"tf":1.0},"76":{"tf":1.4142135623730951},"86":{"tf":1.4142135623730951}},"k":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"21":{"tf":1.7320508075688772}}}}}}},"t":{"a":{"df":0,"docs":{},"l":{"df":2,"docs":{"13":{"tf":1.4142135623730951},"14":{"tf":1.0}}}},"df":0,"docs":{}}},"r":{"a":{"c":{"df":0,"docs":{},"e":{"df":2,"docs":{"52":{"tf":2.23606797749979},"54":{"tf":3.0}}}},"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"13":{"tf":1.0}},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"49":{"tf":1.0}}}}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"66":{"tf":1.0}}}},"n":{"df":0,"docs":{},"s":{"a":{"c":{"df":0,"docs":{},"t":{"df":2,"docs":{"40":{"tf":1.0},"77":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"t":{"df":7,"docs":{"31":{"tf":1.0},"33":{"tf":1.0},"36":{"tf":1.0},"40":{"tf":1.0},"44":{"tf":1.0},"72":{"tf":1.0},"83":{"tf":1.0}}}},"df":0,"docs":{}}}},"p":{"df":3,"docs":{"0":{"tf":1.0},"36":{"tf":1.0},"37":{"tf":1.0}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"e":{"df":1,"docs":{"66":{"tf":1.0}}}},"i":{"df":2,"docs":{"59":{"tf":1.0},"61":{"tf":1.0}},"v":{"df":0,"docs":{},"i":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"67":{"tf":1.0}}}},"df":0,"docs":{}}}},"u":{"df":0,"docs":{},"e":{"df":2,"docs":{"76":{"tf":1.4142135623730951},"88":{"tf":1.0}}}}},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":1,"docs":{"72":{"tf":1.0}}}}},"w":{"df":0,"docs":{},"o":{"df":3,"docs":{"40":{"tf":1.0},"47":{"tf":1.0},"6":{"tf":1.0}}}},"y":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"72":{"tf":1.0}}},"df":0,"docs":{}}}}},"u":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"48":{"tf":2.0}}}}},"l":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"62":{"tf":1.0}}}}}},"n":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"n":{"df":1,"docs":{"67":{"tf":1.0}}}}}}},"c":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":1,"docs":{"62":{"tf":1.0}}}}}},"df":0,"docs":{}},"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":4,"docs":{"19":{"tf":1.0},"3":{"tf":1.0},"59":{"tf":1.0},"64":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":3,"docs":{"40":{"tf":1.0},"49":{"tf":1.0},"75":{"tf":1.0}}}},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"31":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"d":{"df":1,"docs":{"1":{"tf":1.0}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{},"f":{"a":{"df":0,"docs":{},"v":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"72":{"tf":1.0}}}}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"d":{"df":1,"docs":{"88":{"tf":1.0}}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":1,"docs":{"23":{"tf":1.0}}}}}}}},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"w":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"77":{"tf":1.0}}}},"df":0,"docs":{}}},"t":{"df":1,"docs":{"74":{"tf":1.4142135623730951}},"i":{"df":1,"docs":{"53":{"tf":1.0}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"s":{"df":1,"docs":{"7":{"tf":1.0}}}}}}},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"36":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"k":{"df":3,"docs":{"14":{"tf":1.0},"18":{"tf":1.0},"67":{"tf":1.0}}},"n":{"df":0,"docs":{},"k":{"df":1,"docs":{"18":{"tf":1.7320508075688772}}}}}},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"16":{"tf":1.0}}}}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"60":{"tf":1.0}}}},"r":{"df":0,"docs":{},"u":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"34":{"tf":1.0}}}}}}},"u":{"df":0,"docs":{},"s":{"df":1,"docs":{"37":{"tf":1.0}}}},"w":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"61":{"tf":1.0}}}},"df":0,"docs":{}}}},"p":{"d":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"59":{"tf":1.7320508075688772}}}},"df":0,"docs":{}},"df":3,"docs":{"1":{"tf":1.0},"49":{"tf":1.0},"88":{"tf":1.0}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"m":{"df":2,"docs":{"60":{"tf":1.0},"68":{"tf":1.0}}}},"df":0,"docs":{}}}}}},"s":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"19":{"tf":1.0}}}},"df":0,"docs":{},"g":{"df":4,"docs":{"11":{"tf":1.7320508075688772},"51":{"tf":1.7320508075688772},"54":{"tf":1.0},"67":{"tf":1.0}}}},"df":32,"docs":{"13":{"tf":1.7320508075688772},"14":{"tf":1.4142135623730951},"15":{"tf":1.0},"16":{"tf":1.0},"17":{"tf":1.0},"18":{"tf":2.0},"25":{"tf":1.0},"27":{"tf":1.0},"30":{"tf":1.0},"37":{"tf":1.4142135623730951},"40":{"tf":1.7320508075688772},"45":{"tf":1.4142135623730951},"46":{"tf":1.0},"49":{"tf":1.4142135623730951},"5":{"tf":1.0},"50":{"tf":1.0},"52":{"tf":1.0},"58":{"tf":1.7320508075688772},"61":{"tf":1.7320508075688772},"62":{"tf":1.0},"63":{"tf":1.0},"64":{"tf":1.0},"65":{"tf":1.0},"66":{"tf":1.4142135623730951},"67":{"tf":1.0},"68":{"tf":2.0},"72":{"tf":1.0},"74":{"tf":1.0},"78":{"tf":1.0},"79":{"tf":1.0},"8":{"tf":1.0},"85":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":49,"docs":{"1":{"tf":1.0},"10":{"tf":1.0},"11":{"tf":1.0},"12":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"15":{"tf":1.0},"16":{"tf":1.0},"17":{"tf":1.0},"18":{"tf":1.0},"19":{"tf":1.0},"20":{"tf":1.0},"21":{"tf":1.0},"22":{"tf":1.0},"23":{"tf":1.0},"24":{"tf":1.0},"25":{"tf":1.0},"26":{"tf":1.0},"27":{"tf":1.0},"28":{"tf":1.0},"29":{"tf":1.0},"30":{"tf":1.0},"31":{"tf":1.0},"32":{"tf":1.0},"33":{"tf":1.0},"34":{"tf":1.0},"35":{"tf":1.0},"36":{"tf":1.0},"37":{"tf":1.0},"38":{"tf":1.0},"39":{"tf":1.0},"4":{"tf":1.7320508075688772},"40":{"tf":1.0},"41":{"tf":1.0},"42":{"tf":1.0},"43":{"tf":1.0},"44":{"tf":1.0},"45":{"tf":1.0},"46":{"tf":1.0},"47":{"tf":1.0},"48":{"tf":1.0},"49":{"tf":1.4142135623730951},"5":{"tf":1.4142135623730951},"6":{"tf":1.0},"67":{"tf":1.0},"7":{"tf":1.0},"75":{"tf":1.0},"8":{"tf":1.0},"9":{"tf":1.0}}}},"u":{"a":{"df":0,"docs":{},"l":{"df":3,"docs":{"18":{"tf":1.0},"40":{"tf":1.0},"50":{"tf":1.0}}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":2,"docs":{"76":{"tf":1.0},"77":{"tf":1.4142135623730951}}}}}},"v":{"0":{".":{"8":{".":{"0":{"df":1,"docs":{"89":{"tf":1.0}}},"df":0,"docs":{}},"df":1,"docs":{"4":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"df":0,"docs":{}},"1":{".":{"0":{".":{"0":{"df":1,"docs":{"89":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"d":{"df":4,"docs":{"12":{"tf":1.0},"36":{"tf":1.0},"45":{"tf":1.0},"72":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"u":{"df":8,"docs":{"13":{"tf":1.4142135623730951},"14":{"tf":1.4142135623730951},"26":{"tf":1.0},"27":{"tf":1.4142135623730951},"29":{"tf":1.0},"36":{"tf":1.0},"42":{"tf":1.0},"44":{"tf":1.0}},"e":{"_":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"d":{"(":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":1,"docs":{"54":{"tf":1.0}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"i":{"a":{"b":{"df":0,"docs":{},"l":{"df":5,"docs":{"13":{"tf":1.0},"48":{"tf":1.7320508075688772},"52":{"tf":1.0},"61":{"tf":1.0},"79":{"tf":1.0}}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"72":{"tf":1.0}}}}},"df":2,"docs":{"12":{"tf":1.0},"37":{"tf":1.0}},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"20":{"tf":1.0}}}}}}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"76":{"tf":1.0}}}}}}},"df":4,"docs":{"49":{"tf":1.0},"63":{"tf":1.0},"64":{"tf":1.0},"72":{"tf":1.4142135623730951}},"e":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"0":{"tf":1.0}}}}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":2,"docs":{"72":{"tf":1.0},"76":{"tf":1.0}},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"49":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":5,"docs":{"23":{"tf":1.0},"58":{"tf":1.0},"65":{"tf":1.0},"82":{"tf":2.23606797749979},"85":{"tf":2.23606797749979}}}}}}}},"i":{"a":{"df":10,"docs":{"47":{"tf":1.4142135623730951},"48":{"tf":1.0},"60":{"tf":1.0},"65":{"tf":1.4142135623730951},"67":{"tf":1.0},"68":{"tf":1.0},"7":{"tf":1.0},"70":{"tf":1.0},"77":{"tf":1.0},"79":{"tf":1.7320508075688772}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"df":1,"docs":{"48":{"tf":1.4142135623730951}}}},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"48":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":2,"docs":{"88":{"tf":1.7320508075688772},"89":{"tf":1.0}}}},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{".":{"df":0,"docs":{},"r":{"df":1,"docs":{"66":{"tf":1.0}}}},"df":1,"docs":{"66":{"tf":1.4142135623730951}}}}}},"u":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"64":{"tf":1.0}}}},"df":0,"docs":{}}}},"m":{"df":3,"docs":{"40":{"tf":1.0},"49":{"tf":1.4142135623730951},"72":{"tf":1.4142135623730951}}},"s":{"df":3,"docs":{"32":{"tf":1.4142135623730951},"5":{"tf":1.4142135623730951},"69":{"tf":1.0}}}},"w":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":3,"docs":{"54":{"tf":1.0},"66":{"tf":1.0},"68":{"tf":1.0}}}},"r":{"df":0,"docs":{},"m":{"df":1,"docs":{"0":{"tf":1.0}}},"n":{"df":6,"docs":{"0":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"18":{"tf":1.0},"38":{"tf":1.0},"40":{"tf":1.0}}}},"s":{"df":0,"docs":{},"m":{"df":4,"docs":{"7":{"tf":1.0},"72":{"tf":2.8284271247461903},"78":{"tf":1.0},"79":{"tf":2.0}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"72":{"tf":1.4142135623730951}}}}}}},"y":{"df":2,"docs":{"74":{"tf":1.0},"80":{"tf":1.0}}}},"df":0,"docs":{},"e":{"b":{"3":{"df":1,"docs":{"88":{"tf":1.0}}},"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"b":{"df":0,"docs":{},"m":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"72":{"tf":1.0}}}}}},"df":0,"docs":{}}}}},"df":1,"docs":{"88":{"tf":1.0}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":1,"docs":{"54":{"tf":2.449489742783178}}}}}},"l":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"df":4,"docs":{"0":{"tf":2.0},"1":{"tf":1.0},"2":{"tf":1.0},"3":{"tf":1.0}}}}},"df":0,"docs":{},"l":{"df":3,"docs":{"1":{"tf":1.0},"31":{"tf":1.0},"76":{"tf":1.0}}}},"’":{"d":{"df":2,"docs":{"49":{"tf":1.0},"62":{"tf":1.0}}},"df":0,"docs":{}}},"h":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":1,"docs":{"62":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":1,"docs":{"59":{"tf":1.0}}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":1,"docs":{"75":{"tf":1.0}}}}},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"62":{"tf":1.0}}}}}}},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":1,"docs":{"5":{"tf":1.0}}}}}},"i":{"df":0,"docs":{},"e":{"d":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"12":{"tf":1.0}}}}},"df":0,"docs":{}},"n":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":2,"docs":{"62":{"tf":1.0},"7":{"tf":1.0}}}}},"df":0,"docs":{}},"s":{"df":0,"docs":{},"h":{"df":1,"docs":{"62":{"tf":1.4142135623730951}}}}},"o":{"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"’":{"df":1,"docs":{"88":{"tf":1.0}}}},"df":0,"docs":{}},"r":{"d":{"df":2,"docs":{"5":{"tf":1.0},"61":{"tf":1.0}}},"df":0,"docs":{},"k":{"df":7,"docs":{"0":{"tf":1.4142135623730951},"18":{"tf":1.4142135623730951},"40":{"tf":1.4142135623730951},"49":{"tf":1.0},"66":{"tf":1.0},"69":{"tf":1.0},"87":{"tf":1.0}},"l":{"df":0,"docs":{},"o":{"a":{"d":{"df":1,"docs":{"72":{"tf":1.7320508075688772}}},"df":0,"docs":{}},"df":0,"docs":{}}},"s":{"df":0,"docs":{},"p":{"a":{"c":{"df":1,"docs":{"59":{"tf":1.7320508075688772}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"l":{"d":{"df":1,"docs":{"11":{"tf":1.0}}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"36":{"tf":1.0}}}},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"w":{"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"11":{"tf":1.0}}}}}}}}}},"r":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"68":{"tf":1.0},"76":{"tf":1.0}}}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":7,"docs":{"37":{"tf":1.0},"38":{"tf":1.0},"43":{"tf":1.0},"61":{"tf":1.0},"72":{"tf":1.0},"76":{"tf":1.0},"85":{"tf":1.4142135623730951}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":2,"docs":{"49":{"tf":1.4142135623730951},"63":{"tf":1.0}}}}}}}}},"x":{"8":{"6":{"df":1,"docs":{"72":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{},"y":{"df":2,"docs":{"84":{"tf":1.4142135623730951},"86":{"tf":1.4142135623730951}}}},"y":{"df":0,"docs":{},"e":{"df":1,"docs":{"83":{"tf":1.0}}},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"f":{"df":1,"docs":{"62":{"tf":1.0}}}}}}},"’":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":1,"docs":{"58":{"tf":1.0}}}}}}},"u":{"df":0,"docs":{},"l":{"df":12,"docs":{"16":{"tf":1.0},"22":{"tf":1.0},"31":{"tf":1.0},"36":{"tf":1.7320508075688772},"47":{"tf":1.0},"5":{"tf":1.0},"6":{"tf":1.0},"63":{"tf":1.0},"64":{"tf":1.4142135623730951},"66":{"tf":1.7320508075688772},"69":{"tf":1.0},"83":{"tf":1.0}}}}},"z":{"df":1,"docs":{"12":{"tf":1.0}},"k":{"df":1,"docs":{"49":{"tf":1.0}}}}}},"title":{"root":{"2":{"4":{"df":0,"docs":{},"k":{"b":{"df":1,"docs":{"86":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}},"6":{"3":{"/":{"6":{"4":{"df":1,"docs":{"34":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"a":{"d":{"d":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{".":{"c":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"o":{"d":{"df":1,"docs":{"35":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{},"i":{"df":1,"docs":{"62":{"tf":1.0}}},"r":{"c":{"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"63":{"tf":1.0}}}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"f":{"a":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"16":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"s":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"83":{"tf":1.0}}}},"df":0,"docs":{}}}}},"u":{"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"c":{"df":1,"docs":{"1":{"tf":1.0}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"53":{"tf":1.0}}}},"df":0,"docs":{}}}}}},"b":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"7":{"tf":1.0}}}}},"df":0,"docs":{}}},"l":{"df":0,"docs":{},"o":{"b":{"b":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":1,"docs":{"46":{"tf":1.0}}}}}}},"df":0,"docs":{}},"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"df":1,"docs":{"46":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"u":{"df":0,"docs":{},"g":{"df":1,"docs":{"75":{"tf":1.0}}},"i":{"d":{"df":0,"docs":{},"l":{"df":1,"docs":{"10":{"tf":1.0}}}},"df":0,"docs":{},"l":{"d":{"df":1,"docs":{"65":{"tf":1.0}}},"df":0,"docs":{}}}}},"c":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"d":{"a":{"df":0,"docs":{},"t":{"a":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":1,"docs":{"38":{"tf":1.0}}}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"a":{"d":{"df":1,"docs":{"38":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"11":{"tf":1.0}}}},"o":{"d":{"df":0,"docs":{},"e":{"b":{"a":{"df":0,"docs":{},"s":{"df":1,"docs":{"59":{"tf":1.0}}}},"df":0,"docs":{}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":1,"docs":{"39":{"tf":1.0}}}}}},"df":1,"docs":{"32":{"tf":1.4142135623730951}}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"75":{"tf":1.0}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":4,"docs":{"22":{"tf":1.0},"63":{"tf":1.0},"66":{"tf":1.0},"78":{"tf":1.0}}}}}},"n":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"71":{"tf":1.0}}}}}}},"t":{"df":0,"docs":{},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":5,"docs":{"2":{"tf":1.0},"49":{"tf":1.0},"53":{"tf":1.0},"65":{"tf":1.0},"86":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"i":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"60":{"tf":1.0}},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"56":{"tf":1.0}}}}}}},"df":0,"docs":{}}}}}},"p":{"df":0,"docs":{},"u":{"df":1,"docs":{"71":{"tf":1.0}}}},"r":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"40":{"tf":1.0}},"e":{"2":{"df":1,"docs":{"40":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"78":{"tf":1.0}}}}}},"u":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"df":1,"docs":{"69":{"tf":1.0}}}}}}}},"d":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"p":{"df":1,"docs":{"85":{"tf":1.0}}}},"t":{"a":{"df":0,"docs":{},"o":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"41":{"tf":1.0}}}}}}}},"s":{"df":1,"docs":{"42":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{},"e":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"df":2,"docs":{"16":{"tf":1.0},"17":{"tf":1.0}}}}},"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"d":{"df":2,"docs":{"68":{"tf":1.0},"8":{"tf":1.0}}},"df":0,"docs":{}}},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"y":{"df":3,"docs":{"18":{"tf":1.0},"32":{"tf":1.0},"86":{"tf":1.0}}}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":1,"docs":{"55":{"tf":1.0}}}}}}}},"i":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"31":{"tf":1.0},"47":{"tf":1.0}},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":2,"docs":{"76":{"tf":1.0},"77":{"tf":1.0}}}}}}}},"i":{"c":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"44":{"tf":1.0}}}}}}},"df":0,"docs":{}}}}},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":1,"docs":{"87":{"tf":1.0}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":0,"docs":{},"s":{"c":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"79":{"tf":1.0}}}}}}}}},"df":0,"docs":{}}},"n":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"73":{"tf":1.0}}}}}}}},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"u":{"df":0,"docs":{},"m":{"df":1,"docs":{"75":{"tf":1.0}}}}}}}}},"v":{"df":0,"docs":{},"m":{"df":3,"docs":{"31":{"tf":1.0},"67":{"tf":1.0},"82":{"tf":1.0}}}},"x":{"a":{"df":0,"docs":{},"m":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":2,"docs":{"48":{"tf":1.0},"54":{"tf":1.0}}}}}},"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"22":{"tf":1.0}}}}}},"t":{"c":{"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":1,"docs":{"45":{"tf":1.0}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"f":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"86":{"tf":1.0}}}},"q":{"df":1,"docs":{"81":{"tf":1.0}}}},"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":2,"docs":{"36":{"tf":1.0},"37":{"tf":1.0}}}}}}},"df":0,"docs":{}}}},"g":{"a":{"df":1,"docs":{"34":{"tf":1.0}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"57":{"tf":1.0}}}},"u":{"df":0,"docs":{},"i":{"d":{"df":4,"docs":{"4":{"tf":1.0},"55":{"tf":1.0},"56":{"tf":1.0},"61":{"tf":1.0}}},"df":0,"docs":{}}}},"h":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"p":{"df":2,"docs":{"14":{"tf":1.0},"67":{"tf":1.0}}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"73":{"tf":1.0}}}}}},"i":{"d":{"df":1,"docs":{"23":{"tf":1.0}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":1,"docs":{"17":{"tf":1.0}}}},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"48":{"tf":1.0}}}}}}},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"48":{"tf":1.0}}}}},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"83":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"l":{"df":3,"docs":{"51":{"tf":1.0},"6":{"tf":1.0},"8":{"tf":1.0}}},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"53":{"tf":1.0}}}}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"g":{"df":0,"docs":{},"r":{"df":2,"docs":{"20":{"tf":1.0},"76":{"tf":1.0}}}},"r":{"df":0,"docs":{},"f":{"a":{"c":{"df":1,"docs":{"24":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"n":{"df":1,"docs":{"63":{"tf":1.0}}}}}}},"r":{"df":1,"docs":{"47":{"tf":1.0}}}},"j":{"df":0,"docs":{},"s":{"df":1,"docs":{"19":{"tf":1.0}},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"24":{"tf":1.0}}}}}},"l":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"86":{"tf":1.0}}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":1,"docs":{"12":{"tf":1.0}}}}}},"i":{"b":{"c":{"df":1,"docs":{"80":{"tf":1.0}}},"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":2,"docs":{"49":{"tf":1.0},"66":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"k":{"df":1,"docs":{"18":{"tf":1.0}}}}},"l":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{"df":2,"docs":{"12":{"tf":1.0},"68":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"g":{"df":1,"docs":{"52":{"tf":1.0}}}}},"m":{"a":{"df":0,"docs":{},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"58":{"tf":1.0}}}}}}}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":1,"docs":{"37":{"tf":1.0}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":2,"docs":{"37":{"tf":1.0},"67":{"tf":1.0}}}}}}},"l":{"df":0,"docs":{},"o":{"a":{"d":{"df":1,"docs":{"37":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}},"o":{"d":{"df":0,"docs":{},"e":{"df":1,"docs":{"47":{"tf":1.0}}}},"df":0,"docs":{}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"z":{"df":0,"docs":{},"e":{"df":1,"docs":{"37":{"tf":1.0}}}}},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":1,"docs":{"37":{"tf":1.0}}}}}}},"u":{"df":0,"docs":{},"s":{"df":0,"docs":{},"l":{"df":1,"docs":{"80":{"tf":1.0}}}}}},"n":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"5":{"tf":1.0}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"p":{"df":0,"docs":{},"m":{"df":2,"docs":{"19":{"tf":1.0},"9":{"tf":1.0}}}}},"o":{"b":{"df":0,"docs":{},"j":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":3,"docs":{"25":{"tf":1.0},"27":{"tf":1.0},"28":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{},"p":{"c":{"df":0,"docs":{},"o":{"d":{"df":1,"docs":{"84":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":2,"docs":{"12":{"tf":1.0},"69":{"tf":1.0}}}}}},"r":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"48":{"tf":1.0}}}}},"df":0,"docs":{},"g":{"a":{"df":0,"docs":{},"n":{"df":1,"docs":{"59":{"tf":1.0}}}},"df":0,"docs":{}}}},"p":{"a":{"c":{"df":0,"docs":{},"k":{"a":{"df":0,"docs":{},"g":{"df":2,"docs":{"19":{"tf":1.0},"9":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":2,"docs":{"70":{"tf":1.0},"73":{"tf":1.0}}}}}}},"c":{"df":1,"docs":{"45":{"tf":1.0}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"i":{"df":1,"docs":{"62":{"tf":1.0}}}},"df":0,"docs":{}},"k":{"a":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"n":{"d":{"a":{"df":0,"docs":{},"o":{"df":1,"docs":{"44":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"v":{"df":0,"docs":{},"m":{"df":2,"docs":{"70":{"tf":1.0},"72":{"tf":1.0}}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"g":{"a":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"47":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}},"l":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"37":{"tf":1.0}}}},"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"s":{"df":1,"docs":{"7":{"tf":1.0}}}},"df":0,"docs":{}}},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"x":{"df":1,"docs":{"23":{"tf":1.0}}}}},"p":{"df":0,"docs":{},"l":{"a":{"c":{"df":1,"docs":{"87":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"u":{"c":{"df":1,"docs":{"65":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"c":{"df":6,"docs":{"10":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.0},"64":{"tf":1.0},"7":{"tf":1.0},"87":{"tf":1.0}}},"df":0,"docs":{}},"u":{"df":0,"docs":{},"r":{"c":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}}}}},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":1,"docs":{"43":{"tf":1.0}}}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":1,"docs":{"43":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"v":{"df":6,"docs":{"5":{"tf":1.0},"50":{"tf":1.0},"66":{"tf":1.0},"70":{"tf":1.0},"73":{"tf":1.0},"9":{"tf":1.0}}}}}},"o":{"a":{"d":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"p":{"df":2,"docs":{"88":{"tf":1.0},"89":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":2,"docs":{"34":{"tf":1.0},"60":{"tf":1.0}}}},"n":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"50":{"tf":1.0}}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":2,"docs":{"32":{"tf":1.0},"70":{"tf":1.0}}}}}},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"49":{"tf":1.0}}}}}},"s":{"a":{"df":0,"docs":{},"n":{"d":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"x":{"df":1,"docs":{"50":{"tf":1.0}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"s":{".":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"u":{"df":1,"docs":{"30":{"tf":1.0}}}}}},"df":0,"docs":{}}}}},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"28":{"tf":1.0}},"i":{"df":0,"docs":{},"z":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{".":{"df":0,"docs":{},"m":{"df":0,"docs":{},"o":{"d":{"df":1,"docs":{"29":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}}}}},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"k":{"a":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{".":{"d":{"df":0,"docs":{},"e":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"m":{"df":1,"docs":{"26":{"tf":1.0}}}}}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"y":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":1,"docs":{"27":{"tf":1.0}}}}}}}},"df":0,"docs":{}}}}}}}},"df":1,"docs":{"25":{"tf":1.0}}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}}}}}},"i":{"df":0,"docs":{},"z":{"df":0,"docs":{},"e":{"df":3,"docs":{"13":{"tf":1.0},"14":{"tf":1.0},"86":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"l":{"c":{"df":4,"docs":{"15":{"tf":1.0},"47":{"tf":1.0},"8":{"tf":1.0},"87":{"tf":1.0}}},"df":0,"docs":{},"i":{"d":{"df":4,"docs":{"21":{"tf":1.0},"33":{"tf":1.0},"75":{"tf":1.0},"85":{"tf":1.0}}},"df":0,"docs":{}}},"u":{"df":0,"docs":{},"r":{"c":{"df":1,"docs":{"10":{"tf":1.0}}},"df":0,"docs":{}}}},"t":{"a":{"c":{"df":0,"docs":{},"k":{"df":1,"docs":{"13":{"tf":1.0}}}},"df":0,"docs":{},"n":{"d":{"a":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"24":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"t":{"df":1,"docs":{"57":{"tf":1.0}}}},"t":{"df":0,"docs":{},"e":{"df":1,"docs":{"48":{"tf":1.0}}}}},"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"df":1,"docs":{"74":{"tf":1.0}}}}}}},"df":0,"docs":{}},"y":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":1,"docs":{"61":{"tf":1.0}}}}}},"u":{"df":0,"docs":{},"p":{"df":0,"docs":{},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":3,"docs":{"82":{"tf":1.0},"83":{"tf":1.0},"84":{"tf":1.0}}}}}}}}},"t":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":3,"docs":{"1":{"tf":1.0},"70":{"tf":1.0},"71":{"tf":1.0}}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":3,"docs":{"74":{"tf":1.0},"76":{"tf":1.0},"77":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":1,"docs":{"18":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":2,"docs":{"20":{"tf":1.0},"86":{"tf":1.0}},"k":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"21":{"tf":1.0}}}}}}}},"r":{"a":{"c":{"df":0,"docs":{},"e":{"df":1,"docs":{"52":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"u":{"df":0,"docs":{},"s":{"a":{"df":0,"docs":{},"g":{"df":2,"docs":{"11":{"tf":1.0},"51":{"tf":1.0}}}},"df":1,"docs":{"58":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"4":{"tf":1.0}}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"77":{"tf":1.0}}}}}},"v":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"48":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":2,"docs":{"82":{"tf":1.0},"85":{"tf":1.0}}}}}}}},"i":{"a":{"df":2,"docs":{"47":{"tf":1.0},"79":{"tf":1.0}}},"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"88":{"tf":1.0}}}}}}},"s":{"df":2,"docs":{"32":{"tf":1.0},"5":{"tf":1.0}}}},"w":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"m":{"df":1,"docs":{"79":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"df":1,"docs":{"0":{"tf":1.0}}}}},"df":0,"docs":{}}},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":1,"docs":{"85":{"tf":1.0}}}}}}},"x":{"df":0,"docs":{},"y":{"df":2,"docs":{"84":{"tf":1.0},"86":{"tf":1.0}}}},"y":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":1,"docs":{"36":{"tf":1.0}}}}}}}},"lang":"English","pipeline":["trimmer","stopWordFilter","stemmer"],"ref":"id","version":"0.9.5"},"results_options":{"limit_results":30,"teaser_word_count":30},"search_options":{"bool":"OR","expand":true,"fields":{"body":{"boost":1},"breadcrumbs":{"boost":1},"title":{"boost":2}}}}')); \ No newline at end of file diff --git a/docs/user_guide.html b/docs/user_guide.html index e64b6c4..d7282b2 100644 --- a/docs/user_guide.html +++ b/docs/user_guide.html @@ -35,7 +35,7 @@ const path_to_root = ""; const default_light_theme = "light"; const default_dark_theme = "navy"; - window.path_to_searchindex_js = "searchindex-c7304031.js"; + window.path_to_searchindex_js = "searchindex-575cfd18.js"; diff --git a/docs/user_guide/cli.html b/docs/user_guide/cli.html index c0fb25b..d0899ab 100644 --- a/docs/user_guide/cli.html +++ b/docs/user_guide/cli.html @@ -35,7 +35,7 @@ const path_to_root = "../"; const default_light_theme = "light"; const default_dark_theme = "navy"; - window.path_to_searchindex_js = "../searchindex-c7304031.js"; + window.path_to_searchindex_js = "../searchindex-575cfd18.js"; diff --git a/docs/user_guide/differences.html b/docs/user_guide/differences.html index b7a3fc6..2f254bb 100644 --- a/docs/user_guide/differences.html +++ b/docs/user_guide/differences.html @@ -35,7 +35,7 @@ const path_to_root = "../"; const default_light_theme = "light"; const default_dark_theme = "navy"; - window.path_to_searchindex_js = "../searchindex-c7304031.js"; + window.path_to_searchindex_js = "../searchindex-575cfd18.js"; diff --git a/docs/user_guide/installation.html b/docs/user_guide/installation.html index e7d21b9..3fe9375 100644 --- a/docs/user_guide/installation.html +++ b/docs/user_guide/installation.html @@ -35,7 +35,7 @@ const path_to_root = "../"; const default_light_theme = "light"; const default_dark_theme = "navy"; - window.path_to_searchindex_js = "../searchindex-c7304031.js"; + window.path_to_searchindex_js = "../searchindex-575cfd18.js"; diff --git a/docs/user_guide/js.html b/docs/user_guide/js.html index 060381b..f20f2fb 100644 --- a/docs/user_guide/js.html +++ b/docs/user_guide/js.html @@ -35,7 +35,7 @@ const path_to_root = "../"; const default_light_theme = "light"; const default_dark_theme = "navy"; - window.path_to_searchindex_js = "../searchindex-c7304031.js"; + window.path_to_searchindex_js = "../searchindex-575cfd18.js"; diff --git a/docs/user_guide/rust_libraries.html b/docs/user_guide/rust_libraries.html index 58bd0f9..995f318 100644 --- a/docs/user_guide/rust_libraries.html +++ b/docs/user_guide/rust_libraries.html @@ -35,7 +35,7 @@ const path_to_root = "../"; const default_light_theme = "light"; const default_dark_theme = "navy"; - window.path_to_searchindex_js = "../searchindex-c7304031.js"; + window.path_to_searchindex_js = "../searchindex-575cfd18.js"; diff --git a/docs/user_guide/std_json.html b/docs/user_guide/std_json.html index 259a04c..70d59d7 100644 --- a/docs/user_guide/std_json.html +++ b/docs/user_guide/std_json.html @@ -35,7 +35,7 @@ const path_to_root = "../"; const default_light_theme = "light"; const default_dark_theme = "navy"; - window.path_to_searchindex_js = "../searchindex-c7304031.js"; + window.path_to_searchindex_js = "../searchindex-575cfd18.js"; @@ -175,16 +175,16 @@

Standard JSON interface

-

The revive compiler is mostly compatible with the solc standard JSON interface. There are a few additional (PVM related) input configurations:

+

The revive compiler is mostly compatible with the solc standard JSON interface. There are a few differences and additional (PVM related) input configurations:

The settings.polkavm object

Used to configure PVM specific compiler settings.

settings.polkavm.debugInformation

A boolean value allowing to enable debug information. Corresponds to resolc -g.

The settings.polkavm.memoryConfig object

Used to apply PVM specific memory configuration settings.

-

settings.polkavm.memoryConifg.heapSize

+

settings.polkavm.memoryConfig.heapSize

A numerical value allowing to configure the contract heap size. Corresponds to resolc --heap-size.

-

settings.polkavm.memoryConifg.stackSize

+

settings.polkavm.memoryConfig.stackSize

A numerical value allowing to configure the contract stack size. Corresponds to resolc --stack-size.

The settings.optimizer object

The settings.optimizer object is augmented with support for PVM specific optimization settings.

@@ -192,6 +192,63 @@

A single char value to configure the LLVM optimizer settings. Corresponds to resolc -O.

settings.llvmArguments

Allows to specify arbitrary command line arguments to LLVM initialization. Used mainly for development and debugging purposes.

+

The settings.outputSelection object

+

Used to select desired outputs.

+

The “all” (*) wildcard

+

Resolc supports the “all” (*) wildcard for the file-level (first-level) and contract-level (second-level) keys. A file-level key can be either the wildcard or a specific file name, whereas the contract-level key can only be the wildcard for robustness reasons.

+

Thus, output can be requested in 2 ways:

+
// All files and all contracts:
+{
+  "settings": {
+    "outputSelection": {
+      "*": {
+        "*": [/* specific contract-level output fields */],
+        "": [/* specific file-level output fields */]
+      }
+    }
+  }
+}
+
+// Specific files and all their contracts:
+{
+  "settings": {
+    "outputSelection": {
+      "path/to/my/file.sol": {
+        "*": [/* specific contract-level output fields */],
+        "": [/* specific file-level output fields */]
+      },
+      // Rest of files...
+    }
+  }
+}
+
+

The contract-level evm output selection

+
+

Note

+

Currently, resolc supports requesting either the full evm output, or one more level of specificity, such as evm.bytecode.

+
+

When requesting code generation, such as evm.bytecode or evm.assembly, the resolc compilation process additionally needs ast, metadata, irOptimized, and evm.methodIdentifiers selectors. These selectors will be automatically added if code generation is needed, but will only be included in the output if explicitly requested.

+
{
+  "settings": {
+    "outputSelection": {
+      "path/to/my/file1.sol": {
+        // Contracts in this file will generate bytecode.
+        // Only these fields of the JSON output selection will be in the `contracts` output.
+        "*": ["abi", "evm.methodIdentifiers", "metadata", "evm.bytecode"],
+        // Only this field of the JSON output selection will be in the `sources` output.
+        "": ["ast"]
+      },
+      "path/to/my/file2.sol": {
+        // No contracts in this file will generate bytecode.
+        "*": ["abi", "evm.methodIdentifiers", "metadata"],
+        // No `ast` will be in the `sources` output (only the automatically added `id`,
+        // similar to solc as this is not a configurable output selection).
+        "": []
+      },
+    }
+  }
+}
+
diff --git a/docs/user_guide/tooling.html b/docs/user_guide/tooling.html index 5012568..8348d13 100644 --- a/docs/user_guide/tooling.html +++ b/docs/user_guide/tooling.html @@ -35,7 +35,7 @@ const path_to_root = "../"; const default_light_theme = "light"; const default_dark_theme = "navy"; - window.path_to_searchindex_js = "../searchindex-c7304031.js"; + window.path_to_searchindex_js = "../searchindex-575cfd18.js"; diff --git a/docs/welcome.html b/docs/welcome.html index 4fed031..03cbbb9 100644 --- a/docs/welcome.html +++ b/docs/welcome.html @@ -35,7 +35,7 @@ const path_to_root = ""; const default_light_theme = "light"; const default_dark_theme = "navy"; - window.path_to_searchindex_js = "searchindex-c7304031.js"; + window.path_to_searchindex_js = "searchindex-575cfd18.js"; diff --git a/js/emscripten/fixtures/instantiate.json b/js/emscripten/fixtures/instantiate.json index 0e59398..243081b 100644 --- a/js/emscripten/fixtures/instantiate.json +++ b/js/emscripten/fixtures/instantiate.json @@ -12,7 +12,7 @@ }, "outputSelection": { "*": { - "*": ["abi"] + "*": ["abi", "evm.bytecode"] } } } diff --git a/js/emscripten/fixtures/instantiate_tokens.json b/js/emscripten/fixtures/instantiate_tokens.json index 773f654..eab33a9 100644 --- a/js/emscripten/fixtures/instantiate_tokens.json +++ b/js/emscripten/fixtures/instantiate_tokens.json @@ -72,7 +72,7 @@ }, "outputSelection": { "*": { - "*": ["abi"] + "*": ["abi", "evm.bytecode"] } } } diff --git a/js/emscripten/fixtures/storage.json b/js/emscripten/fixtures/storage.json index e95a3c9..529a8ea 100644 --- a/js/emscripten/fixtures/storage.json +++ b/js/emscripten/fixtures/storage.json @@ -12,7 +12,7 @@ }, "outputSelection": { "*": { - "*": ["abi"] + "*": ["abi", "evm.bytecode"] } } } diff --git a/js/emscripten/fixtures/token.json b/js/emscripten/fixtures/token.json index b62e941..5754e88 100644 --- a/js/emscripten/fixtures/token.json +++ b/js/emscripten/fixtures/token.json @@ -72,7 +72,7 @@ }, "outputSelection": { "*": { - "*": ["abi"] + "*": ["abi", "evm.bytecode"] } } }